61 votes

Comparaison des ORM .net

Je discutais avec quelqu'un de l'Entity Framework, et je ne suis pas encore vraiment à fond dedans, mais j'aimerais l'apprendre. Cependant, je ne sais toujours pas si je dois l'apprendre ou non. J'ai entendu beaucoup de personnes dire qu'il ne fallait pas utiliser l'Entity Framework, mais je n'ai pas entendu d'arguments en ce sens.

Ma question est donc la suivante : quels sont les avantages et les inconvénients de l'utilisation d'Entity Framework ? par rapport à d'autres produits . Comme

  • NHibernate
  • DataObjects.Net
  • etc.

En termes de facilité d'utilisation, de testabilité, de sémantique...

Je sais qu'il y a des duplicate questions à ce sujet. Mais ils sont tous un peu dépassés (2008, 2009) et pour être honnête, les arguments manquent aussi de quelque chose. Je sais qu'Entity Framework 4.0 est disponible, mais je n'ai pas encore trouvé de bonne comparaison (complète).


Réponses

Certaines personnes sympathiques ici ont répondu à ma question en expliquant quelques détails sur les différents cadres. J'ai pensé qu'il serait bon de les montrer ici pour référence future.

52voto

Diego Mijelshon Points 40314

Comme J. Tihon a fait un excellent travail d'explication des fonctionnalités d'EF, je vais me contenter de lister les domaines où NHibernate tourne autour d'EF :

  • Mise en cache
    • EF n'a rien qui sorte de l'ordinaire ; il y a juste une échantillon non étayé
    • NH dispose d'un support complet pour la mise en cache, y compris l'invalidation basée sur la base de données. Il est également extensible et basé sur les fournisseurs, ce qui signifie qu'il fonctionne avec différents types de caches locaux et distribués.
  • Batching
    • EF n'en a pas
    • NH offre une prise en charge étendue du chargement paresseux de groupes d'entités ou de collections en une seule fois (dans n'importe quelle base de données), et de la persistance des modifications de la même manière (Oracle et SQL Server). Il y a aussi MultiQueries et Future Queries, qui vous permettent de grouper arbitrairement différentes requêtes à envoyer en un seul aller-retour.
  • Types d'utilisateurs
    • EF n'est pas du tout extensible. Il ne supporte même pas les propriétés Enum
    • Aucun mappage de type n'est codé en dur dans NH. Vous pouvez l'étendre pour prendre en charge tous les types de valeurs que vous pouvez créer, modifier la façon dont les types existants sont mis en correspondance, etc.
  • Soutien aux collections
    • EF ne supporte que les collections simples d'entités. Le Many-to-Many utilise toujours une clé composite
    • NH supporte les collections d'entités, de types de valeurs, de types de composants, ainsi que les collections indexées et les dictionnaires (où la clé et la valeur peuvent être de n'importe quel type). Les collections Many-to-Many avec leur propre clé sont supportées (idbag).
  • Enregistrement
    • EF ne dispose d'aucune journalisation. Il y a le même échantillon non supporté listé ci-dessus
    • NH dispose d'un système de journalisation étendu, vous permettant de déboguer facilement les problèmes. Il utilise log4net par défaut, mais vous pouvez utiliser le framework de journalisation de votre choix.
  • Interrogation de
    • EF utilise LINQ comme principal langage d'interrogation. LINQ a une impédance élevée lors de la mise en correspondance avec des bases de données relationnelles. Le fournisseur d'EF ne prend pas en charge l'utilisation d'entités comme paramètres ; vous devez toujours utiliser des Ids. Il existe également un langage de requête qui est mal documenté.
    • NH dispose de LINQ (pas aussi complet que celui de EF, cependant), HQL, QueryOver et Criteria.
  • Système d'événements et intercepteurs
    • EF n'a presque rien
    • NH dispose d'un puissant système d'événements qui vous permet d'étendre ou de remplacer son comportement à n'importe quel moment du cycle de vie de la session : chargement des objets, persistance des modifications, vidage, etc.

Je pense que l'extensibilité est le principal argument de vente. Chaque aspect de NH est correctement découplé du reste, en utilisant des interfaces et des clases de base que vous pouvez étendre quand vous en avez besoin, et exposées dans les options de configuration.

EF suit le modèle habituel de MS qui consiste à rendre les choses fermées par défaut, et nous verrons plus tard ce qui est extensible.

34voto

J. Tihon Points 3519

J'ai passé énormément de temps à adapter l'Entity Framework à mes besoins et je peux donc dire qu'il remplit la plupart des conditions que vous attendez d'un ORM. Mais certains aspects sont beaucoup trop complexes, car d'autres ORM ont montré qu'il est possible de les rendre plus faciles.

Par exemple, il est assez facile de démarrer avec Entity Framework, puisqu'il suffit de lancer le Designer dans Visual Studio pour disposer d'un ORM fonctionnel en quelques minutes. Mais on se retrouve avec des classes d'entités liées au contexte d'objet créé par le concepteur (on peut éviter cela en utilisant un modèle T4 personnalisé). Ce n'est pas nécessairement une mauvaise chose, mais c'est le genre d'approches Microsoft "Getting Started" que vous ne voulez pas utiliser dans une application réelle.

Mais si vous vous plongez plus profondément dans l'Entity Framework, vous verrez comment vous pouvez éviter la plupart de ses pièges : Le Designer génère un fichier EDMX, qui (si vous le regardez dans un éditeur XML) n'est rien de plus qu'une combinaison des trois aspects principaux d'un ORM, le stockage physique (votre base de données), le modèle conceptuel (vos classes d'entités) et le mapping entre les deux. L'action de construction personnalisée appliquée aux fichiers .edmx dans Visual Studio divise ces trois parties en trois fichiers distincts et les ajoute à l'assemblage en tant que ressources intégrées. Lors de la création d'un ObjectContext, le chemin vers ces trois fichiers est utilisé dans la ConnectionString (ce qui me semble toujours un peu confus). Ce que vous pouvez faire ici, c'est faire tout cela vous-même. Cela signifie écrire le schéma de stockage, le modèle conceptuel et le mappage dans un éditeur XML (un peu comme NHibernate) et les intégrer à l'assemblage contenant votre modèle.

La classe de base d'Entity Framework "ObjectContext" peut être construite à partir de ces trois fichiers (elle prend un MetadataWorkspace et une EntityConnection), mais le fait est que vous avez un contrôle total sur la façon dont l'ObjectContext est créé. Cela ouvre la porte à de nombreuses fonctionnalités que vous n'attendiez pas de l'Entity Framework. Par exemple : vous pouvez intégrer plusieurs schémas de stockage SSDL dans le même assembly pour correspondre à un type de base de données spécifique (j'en ajoute généralement un pour SQL Server et un pour SQL Server CE 4.0). Et créer une surcharge de constructeur qui choisit le schéma de stockage approprié pour un type spécifique de DbConnection.

Puisque vous avez maintenant votre propre implémentation d'ObjectContext, vous pouvez implémenter diverses interfaces sur celui-ci. Comme votre propre IRepository, mais comme j'aime l'approche ObjectContext, je crée quelque chose comme :

interface ICatalog
{
    IEntitySet<Article> { get; }
    void Save();
}

interface IEntitySet<T> : IQueryable<T>
{
    void Add(T);
    void Remove(T); 
}

class EntityFrameworkCatalog : ICatalog
{
    ...
}

Mais créer un Repository si vous avez un ObjectContext d'Entity Framework est très facile, et vous obtenez en plus un IQueryable. Sur la base de ces informations, vous pouvez éviter d'avoir un fort couplage de classes entre vos services et l'ORM et éliminer complètement l'Entity Framework dans les tests. De plus, lorsque vous testez l'implémentation de votre Entity Framework, vous pouvez utiliser une base de données SQL Server CE pendant les tests unitaires pour vous assurer que vos mappings sont corrects (généralement, la différence entre le schéma de stockage pour CE et le SQL Server complet se limite à quelques types de données). Vous pouvez donc tester tous les comportements de votre implémentation Entity Framework sans problème.

Ainsi, Entity Framework s'inscrit parfaitement dans les concepts des logiciels modernes, mais il ne vous impose pas de telles pratiques, ce qui facilite la "prise en main".

Passons maintenant aux éléments complexes : L'Entity Framework dispose d'un petit ensemble de types CLR pris en charge, qui ne comprend essentiellement que les types primitifs, comme les ints, les chaînes de caractères et les tableaux d'octets. Il fournit également un certain niveau de types complexes, qui suivent les mêmes règles. Mais que se passe-t-il si vous avez une propriété d'entité complexe telle que la représentation DOM d'un document, que vous souhaitez sérialiser en XML dans la base de données. Pour autant que je sache, NHibernate fournit une fonctionnalité appelée IUserType, qui vous permet de définir un tel mappage pour vous. Dans Entity Framework, cela devient beaucoup plus compliqué, mais c'est toujours joli à sa façon. Le modèle conceptuel vous permet d'inclure des types complexes internes à l'assemblage (pour autant que vous en informiez l'ObjectContext (ObjectContext.CreateProxyTypes(Type[])). Ainsi, vous pouvez créer un wrapper pour votre type original, qui n'est connu que de l'Entity Framework, comme suit :

 class Document : IXmlSerializable { }
 class Article
 {
     public virtual Document Content { get; set; }
 }
 internal class EntityFrameworkDocument : Document
 {
     public string Xml
     {
         get
         {
              // Use XmlSerializer to generate the XML-string for this instance.
         }
         set
         {
              // Use XmlSerializer to read the XML-string for this instance.
         }
     }
 }

Bien que EF puisse maintenant retourner ces documents sérialisés depuis le stockage, les écrire dans le stockage nécessite d'intercepter le stockage d'un article et de remplacer un simple document par un EntityFrameworkDocument, pour s'assurer que EF peut le sérialiser. Je suis sûr que d'autres ORMs font cela assez facilement, et c'est encore pire. Actuellement, il n'y a aucun moyen de faire la même chose avec la classe System.Uri (qui est immuable, mais qui fonctionnerait autrement) ou une Enum. En dehors de ces restrictions, vous pouvez adapter l'EF à la plupart de vos besoins. Mais vous y passerez beaucoup de temps (comme je l'ai fait).

Comme mon expérience des autres ORM est limitée, je résumerai :

  • Entity Framework est dans le GAC, même dans le profil du client.
  • Entity Framework peut être personnalisé pour représenter des types d'entités même complexes (y compris des entités many-to-many auto-référencées, par exemple, ou la sérialisation XML ci-dessus).
  • Il peut être "abstrait", de sorte que vous pouvez vous en tenir à IRepository, etc.
  • Implémentation de IQueryable (bien qu'elle ne soit pas aussi complète que DataObjects.Net)
  • Elle ne nécessite que System.Data et System.Data.Entity. Vous pouvez même inclure plusieurs schémas de stockage pour d'autres fournisseurs, ce qui nécessiterait normalement une référence, mais si vous vous en tenez à DbConnection, vous pouvez simplement le faire :

    ICatalog Create(DbConnection connection, string storageSchemaPath) ICatalog CreateMySql(DbConnection mySqlConnection) { return Create(connection, "res://Assembly/Path.To.Embedded.MySql.Storage.ssdl"); }

Modifier J'ai récemment découvert que si vos entités et votre implémentation "catalogue" se trouvent dans la même assemblée, vous pouvez utiliser les propriétés internes pour un processus de sérialisation XML. Ainsi, au lieu de dériver une propriété interne EntityFrameworkDocument de Document vous pourriez ajouter une propriété interne appelée Xml à la Document elle-même. Cela ne s'applique toujours que si vous avez le contrôle total de vos entités, mais cela supprime la nécessité d'intercepter toute modification du catalogue, pour s'assurer que votre classe dérivée est utilisée. La CSDL se présente de la même manière, EF permet simplement à la propriété mappée d'être interne. Je dois encore m'assurer que cela fonctionne dans les environnements de confiance moyenne.

11voto

Dean Points 3017

6voto

Eduardo Points 916

Lorsque nous utilisons ADO.NET à partir de zéro, tôt ou tard, nous sommes frustrés et nous commençons à chercher d'autres solutions. J'en ai testé beaucoup. La plupart de ces frameworks ORM ont beaucoup de fonctionnalités et nécessitent beaucoup de connaissances. Certains semblent très faciles au début (ex : EF, Castle ActiveRecord) mais il y a beaucoup de choses dont vous devez tenir compte :

  • Mise en cache
  • Relations entre plusieurs personnes
  • Chargement paresseux
  • Héritage
  • Clés composites
  • Comment encapsuler l'infrastructure des appelants ?
  • Comment les instructions SQL sont générées
  • Performance
  • Comment faire des requêtes avancées sur les bases de données

Si vous êtes un développeur expérimenté et que vous êtes prêt à affronter tous ces pièges, je vous le demande : Vos collègues le sont aussi ?

Il existe des moyens plus simples de coder ADO.NET sans perdre le contrôle de ce qui se passe. Jetez un coup d'œil à IndoloreDAL .

Un codage "élégant" n'est pas toujours le meilleur moyen.

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