web-dev-qa-db-fra.com

Entity Framework avec de grands systèmes - comment diviser les modèles?

Je travaille avec une base de données SQL Server avec plus de 1000 tables, quelques centaines de vues et plusieurs milliers de procédures stockées. Nous cherchons à commencer à utiliser Entity Framework pour nos nouveaux projets, et nous travaillons sur notre stratégie pour le faire. La chose à laquelle je raccroche est la meilleure façon de diviser les tables en différents modèles (EDMX ou DbContext si nous allons d'abord coder). Je peux penser à quelques stratégies dès le départ:

  • divisé par schéma
    Nous avons nos tables réparties sur probablement une douzaine de schémas. Nous pourrions faire un modèle par schéma. Ce n'est pas parfait, cependant, car dbo finit toujours par être très grand, avec plus de 500 tables/vues. Un autre problème est que certaines unités de travail finiront par devoir effectuer des transactions qui s'étendent sur plusieurs modèles, ce qui ajoute à la complexité, bien que je suppose qu'EF rend cela assez simple.
  • Divisé par intention
    Au lieu de vous soucier des schémas, divisez les modèles par intention. Nous aurons donc des modèles différents pour chaque application, ou projet, ou module, ou écran, selon la granularité que nous voulons obtenir. Le problème que je vois avec cela est qu'il y a certaines tables qui doivent inévitablement être utilisées dans tous les cas, comme User ou AuditHistory. Ajoutons-nous ceux-ci à chaque modèle (viole DRY je pense), ou sont-ils dans un modèle distinct utilisé par chaque projet?
  • Ne vous séparez pas du tout - un modèle géant
    C'est évidemment simple du point de vue du développement, mais d'après mes recherches et mon intuition, cela semble pouvoir fonctionner terriblement, à la fois au moment de la conception, de la compilation et éventuellement de l'exécution.

Quelle est la meilleure pratique pour utiliser EF contre une si grande base de données? Plus précisément, quelles stratégies les gens utilisent-ils pour concevoir des modèles par rapport à ce volume d'objets DB? Y a-t-il des options auxquelles je ne pense pas qui fonctionnent mieux que ce que j'ai ci-dessus?

De plus, est-ce un problème dans d'autres ORM tels que NHibernate? Si oui, ont-ils trouvé de meilleures solutions que EF?

52
RationalGeek

Personnellement, j'ai essayé de créer un énorme schéma pour toutes mes entités sur un projet assez complexe mais petit (~ 300 tables). Nous avions une base de données extrêmement normalisée (normalisation de 5ème forme (je le dis vaguement)) avec de nombreuses relations "plusieurs à plusieurs" et une application extrême de l'intégrité référentielle.

Nous avons également utilisé une stratégie "instance unique par demande" qui ne me semble pas non plus avoir aidé.

Lorsque vous effectuez des listes simples et raisonnablement plates "définies explicitement", les recherches et les sauvegardes sont généralement acceptables. Mais quand nous avons commencé à creuser dans des relations profondes, la performance a semblé prendre des baisses drastiques. Comparé à un proc stocké dans ce cas, il n'y avait pas de comparaison (bien sûr). Je suis sûr que nous aurions pu peaufiner la base de code ici et là pour améliorer les performances, cependant, dans ce cas, nous avions juste besoin d'une amélioration des performances sans analyse en raison de contraintes de temps, et nous sommes revenus au proc stocké (toujours mappé) à travers EF, car EF a fourni des résultats fortement typés), nous n'en avions besoin que comme repli dans quelques domaines. Lorsque nous avons dû parcourir toute la base de données pour créer une collection (en utilisant .include () de manière inimitable), les performances se sont sensiblement dégradées, mais nous demandions peut-être trop.

Sur la base de mon expérience, je recommanderais donc de créer un .edmx distinct par intention. Générez uniquement ce que vous utiliserez en fonction de l'étendue de ce besoin. Vous pouvez avoir des fichiers .edmx de portée plus petite pour les tâches prévues, puis des fichiers volumineux où vous devez parcourir des relations complexes pour créer des objets. Je ne sais pas où est ce point magique, mais je suis sûr qu'il y en a un ... lol ...

Honnêtement cependant, à part quelques pièges que nous avons vu venir (traversée complexe), l'énorme .edmx a bien fonctionné d'un point de vue "fonctionnel". Mais vous devrez faire attention à la magie de "correction" que le contexte fait derrière la scène si vous ne la désactivez pas explicitement. En plus de garder le .edmx synchronisé lorsque des modifications sont apportées à la base de données .. il était parfois plus facile d'effacer toute la surface et de recréer les entités, ce qui prenait environ 3 minutes, donc ce n'était pas un gros problème.

Tout cela avec EntityFramework 4.1. Je serais vraiment intéressé à entendre parler de votre choix final et de votre expérience.

Et en ce qui concerne votre question sur nHibernate, c'est une question de vers à mon avis, vous allez aboyer des deux côtés de la clôture ... J'entends beaucoup de gens dénigrer EF pour le dénigrer sans travailler à travers le défis et compréhension des nuances propres à EF lui-même .. et bien que je n'ai jamais utilisé nHibernate dans la production, généralement, si vous devez créer manuellement et explicitement des choses comme les mappages, vous obtiendrez un contrôle plus fin, cependant, si vous peut glisser-déposer, générer et démarrer CRUD et interroger à l'aide de LINQ, je pourrais donner une merde sur la granularité.

J'espère que ça aide.

32
hanzolo

Permettez-moi de commencer par une simple clarification: je n'ai pas d'expérience avec une base de données aussi volumineuse, donc le reste de ma réponse n'est pas basé sur l'exemple du monde réel.

Vous avez donc une GRANDE base de données et vous souhaitez l'utiliser avec ORM/EF. J'irais avec le deuxième choix. Voici mon explication simple pourquoi:

  • La cartographie ajoute de la complexité. Il n'est pas nécessaire d'ajouter de la complexité aux entités dont votre application/projet/module actuel n'a jamais besoin mais ne faites pas un niveau de granularité trop bas. Avoir un jeu de mappage séparé par écran ne vous aidera pas non plus.
  • Vous souhaitez réaliser l'unité de travail. Vous devriez être en mesure de spécifier les modules dont les modules ont besoin dans la plupart des cas (pas nécessaire dans tous les cas). Si vous placez ces tables dans un ensemble de mappage unique, vous pourrez gérer la lecture et la modification des données par instance de contexte unique - c'est ce qui devrait être votre cible ultime.
  • Je ne sais pas exactement ce que vous entendez par modèle, mais même avec différents ensembles de mappage, vous pouvez partager des classes entre des ensembles de mappage en utilisant les mêmes types d'entité. Donc, si vous utilisez la table User dans deux modules, vous n'avez pas besoin de deux classes User pour représenter la même chose. Vous pouvez toujours utiliser une seule table et en cas de mappage de code (aka code-first), vous pouvez même définir le mappage une fois et le charger dans plusieurs jeux de mappage afin que le principe DRY ne soit pas violé mais le code -la première approche a plus de limites en ce qui concerne les vues et les procédures stockées. EDMX rend cela plus difficile. Vous pouvez toujours réutiliser les classes mais réutiliser le mappage impossible.
  • Qu'en est-il des requêtes inter-modules? Ces requêtes peuvent se produire, mais pour être honnête, tout ne doit pas être géré par EF. Vous pouvez profiter d'EF pour les cas courants pour simplifier l'accès régulier aux données, mais si vous avez besoin d'une requête spéciale qui joint les tables appartenant à 5 modules différents, vous pouvez simplement l'exécuter directement ou l'encapsuler dans une procédure stockée. Le remplacement à 100% de l'accès aux données natives peut être difficile, complexe et contre-productif.
  • Le dernier point est simplement pratique: je ne crois pas que l'outillage VS soit prêt à fonctionner avec un si grand ensemble d'objets - pas dans le concepteur, pas même avec l'outil d'importation. Je travaillais sur une très grande base de données avec un accès traditionnel aux données et un projet SQL Database dans VS2008 - l'expérience utilisateur avec un projet complexe était très mauvaise. Vous devez garder le nombre de tables utilisées faible - le plafond pour le concepteur doit être compris entre 100 et 200, mais même 100 tables gérées par un seul contexte (ensemble de mappage) semblent trop de responsabilité pour une classe (supposons que vous aurez 100 propriétés d'ensemble exposé sur le contexte - il ne ressemble pas à un bon design).
13
Ladislav Mrnka

Je dirais que vous ne pouvez pas décider ce genre de question d'un point de vue technique. Je vous recommande de construire votre architecture en fonction de vos cas d'utilisation (user stories, etc.). Trouvez d'abord vos objets métier. Un objet entité n'est pas par défaut un objet métier. Typiquement, vous aurez un objet métier devant les objets entité. Ensuite, vous pouvez décider de manière incrémentielle ce dont vous avez vraiment besoin, en fonction des besoins des utilisateurs.

"Un bon architecte maximise le nombre de décisions non prises." Robert C. Martin

http://cleancoder.posterous.com/architecture-deference

4
ollins

J'utilise une approche hybride - OLTP les choses sont gérées par EF tandis que les opérations lourdes telles que les insertions par lots, les mises à jour en masse, les requêtes de rapport, etc. sont gérées par Stored Procs. Cela facilite également le chemin de migration si vous ne faites pas une réécriture complète de votre couche de données à la fois.

3
Nik