Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Matthieu MEZIL

I love .Net

Abonnements

I autre (meilleur ?) moyen de faire du POCO

Si vous voulez travailler avec des entités POCO et garder dans le même temps les fonctionnalités du contexte comme le tracking des modifications, l’attachement automatique des entités liées, le lazy loading, EF va générer un proxy qui hérite de vos entités (un proxy par entité) et qui va ajouter le code pour faire cela. C’est le même fonctionnement qu’avec N-Hibernate. Cependant, je pense que c’est vraiment pas terrible comme approche. En effet, c’est super contraignant : vos entités ne doivent pas être sealed et doivent être public, tous vos get et set doivent être protected ou public et virtual, il faut avoir un constructeur public ou protected sans paramètre. A cuase de ces contraintes, je n’aime pas cette approche.

Je ne pense (j’espère) d’ailleurs ne pas être le seul dans ce cas. Maintenant c’est facile de critiquer mais comment faire mieux ?

Mon idée était de modifier directement l’assembly des entités plutôt que de passer par des proxy qui en héritent. Sur les conseils de Simon, j’ai utilisé Cecil pour cela.

Comment ça marche ?

J’ai défini un programme qui prend deux paramètres dans la méthode Main : le chemin de l’assembly initial et le chemin de l’edmx. Dans mon program, j’injecte de l’IL dans mes entités afin de leur faire implémenter INotifyPropertyChanging, INotifyPropertyChanged, IEntityWithChangeTracker, IEntityWithKey et IEntityWithRelationships.

Je vais vous épargnez l’IL, ça m’évitera les commentaires du style OMG. Smile Cependant, je vous invite à télécharger le code si cela vous intéresse.

Ensuite, dans mon application, j’utilise le post-build event suivant :

"D:\Documents\Visual Studio 2010\Projects\EF POCO with Cecil\EFPOCOWithCecil\bin\Release\EFPOCOWithCecil.exe" "$(TargetDir)Entities.dll" "$(ProjectDir)..\DAL\Northwind.edmx"

Avec cette implémentation, je peux profiter des fonctionnalités du contexte.

Je n’ai qu’une seule restriction : les navigation properties de type collection doivent être définies comme des ICollection<T> (c’est pareil avec EF mais ça ne me choque pas contrairement aux contraintes que j’évoquais au début).

Le bon point avec cette façon de faire est le fait je n’ai plus les contraintes des proxies. De plus, avec EF, si vous utilisez la méthode CreateObject du contexte, vous allez avoir une instance du proxy. Si vous utilisez le constructeur directement , vous n’allez pas avoir une instance du proxy mais de votre propre classe (donc vous perdez les fonctionnalités du contexte). Ce point est un peu perturbant pour les développeurs débutant. Avec mon approche, ce problème est également résolu.

Vous pouvez télécharger mon code ici.

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Publié jeudi 31 décembre 2009 03:50 par Matthieu MEZIL

Commentaires

# re: I autre (meilleur ?) moyen de faire du POCO @ vendredi 1 janvier 2010 00:49

Et si je veux garder mo objet POCO simple dans d'autres couches par exemple ?

Mitsu

# re: I autre (meilleur ?) moyen de faire du POCO @ vendredi 1 janvier 2010 09:25

Pas sûr de comprendre mais si tu veux garder ton objet POCO simple sans y toucher, tu peux mais tu ne bénéficieras pas des fonctionnalités du contexte que j'évoquais au début. A noter que dans ce cas, les modifications seront automatiquement détectées lors du SaveChanges ou lors de l'appel de la méthode DetectChanges.

Ce qu'il faut également voir c'est que je modifie la dll du répertoire de l'exe. Donc si tu utilises la dll de tes entités dans un autre projet, elle ne sera pas modifiée.

Matthieu MEZIL

# re: I autre (meilleur ?) moyen de faire du POCO @ mardi 5 janvier 2010 11:39

Bonne année Matt !!!

Grace à toi j’ai fait connaissance avec  Cecil, et je n’ai rien à dire techniquement sur ton post.

Mais je ne partage pas tes critiques : le faite que l’entité ne doit pas être sealed ou doit être public, c’est un contrainte Nhibernate mais une entité business est amenée à évoluer dans le temps avec le métier et en plus qu’est ce qu’on peut faire avec des entités qui ne sont pas public, normalent toutes les couches techniques et business gravitent autour des entités du domaines.

Pour les Get et surtout les Set, c’est contraignent, car on veut  limiter la responsabilité de modification aux classes business (j’aime pas trop cette approche) ou plutot au code métier des entités.

Pour le constructeur par défaut, c’est une vraie limitation, mais on peut facilement la détourner en limitant la création des entités à des factories (pas dans le sens pattern).

Et finalement, pour le virtual, Hibernate en Java n’a pas cette problématique car tous est virtuel en Java par défaut. Je trouve que placer une propriété en virtuel ne pose pas de problème si on sait ce qui va se passer derrière.

La dernière remarque d’ordre déontologique est  ce qu’il vaut mieux utiliser un pattern connu « proxy » ou plutôt modifier le code de l’assembly ?  

rochdi

# re: I autre (meilleur ?) moyen de faire du POCO @ mardi 5 janvier 2010 13:05

Une petite précision concernant le virtual en NHibernate. Il y a une raison pour laquelle NHibernate force tous les membres d'une entité d'être en virtual et ce n'est pas par plaisir ou parce qu'en Java c'était comme ça. C'est pour permettre de faire du "vrai" POCO. Sinon comment intercepter les méthodes et les propriétés ?

tja

# re: I autre (meilleur ?) moyen de faire du POCO @ mardi 5 janvier 2010 23:55

@ Rochdi :

"qu’est ce qu’on peut faire avec des entités qui ne sont pas public"

Une entité non public peut malgré tout être exposé via une interface.

"Je trouve que placer une propriété en virtuel ne pose pas de problème si on sait ce qui va se passer derrière"

C'est bien là le problème. On ne maîtrise pas le code derrière.

"La dernière remarque d’ordre déontologique est  ce qu’il vaut mieux utiliser un pattern connu « proxy » ou plutôt modifier le code de l’assembly ?"

Modifier l'assembly pose des problèmes : par exemple, le fait de perdre le debug car les pdb ne sont plus bons. Inversement, contrairement au Proxy, c'est une approche plus performante et non contraignante.

Matthieu MEZIL

Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- SQL Server : Query Notification ou comment être notifié de modifications de données côté application (SqlDependency) par SQL Server vu par Christian Robert le il y a 4 heures et 27 minutes

- [WF4] Un Binding Activity/ActivityDesigner qui passe mal? par Blog de Jérémy Jeanson le il y a 5 heures et 50 minutes

- MyTIC – SharePoint 2010 : déjà un mythe Microsoft ? par Le Blog (Vert) d'Arnaud JUND le il y a 10 heures et 39 minutes

- TechDays 2010 Genève : Retrouvez-moi pour une session sur la Haute disponibilité et le ScaleOut avec SQL Server par SQL Server vu par Christian Robert le 03-18-2010, 15:45

- [MIX10] Keynote deuxième journée – Internet Explorer 9, Html5, Visual Studio 2010, OData par Atteint de JavaScriptite Aiguë [Cyril Durand] le 03-17-2010, 19:40

- Certifications beta .NET 4 par Kévin Gosse le 03-17-2010, 19:33

- [Mix 2010] – Microsoft Translator Technology Preview V2 par RedoBlog - The .NET Gentleman !!! le 03-17-2010, 18:53

- Lancement en Preview de Cyclone lors des TechDays 2010! par Blog de Frédéric Queudret le 03-17-2010, 16:30

- [WP7] Je ne veux pas d’un nouvel iPhone par Le blog de FremyCompany le 03-17-2010, 13:11

- [WF4] Pourquoi utiliser le ContentPresenter dans l’ActivityDesigner? par Blog de Jérémy Jeanson le 03-17-2010, 07:54