Entity Framework mit großen Systemen - wie teilt man Modelle?


50

Ich arbeite mit einer SQL Server-Datenbank mit über 1000 Tabellen, einigen hundert Ansichten und mehreren tausend gespeicherten Prozeduren. Wir möchten Entity Framework für unsere neueren Projekte verwenden und arbeiten an unserer Strategie dafür. Ich möchte wissen, wie ich die Tabellen am besten in verschiedene Modelle aufteilen kann (EDMX oder DbContext, wenn wir zuerst Code verwenden). Ich kann mir auf Anhieb ein paar Strategien vorstellen:

  • Nach Schema
    aufteilen Wir haben unsere Tabellen auf wahrscheinlich ein Dutzend Schemata aufgeteilt. Wir könnten ein Modell pro Schema erstellen. Dies ist jedoch nicht perfekt, da dbo mit über 500 Tabellen / Views immer noch sehr groß ist. Ein weiteres Problem ist, dass bestimmte Arbeitseinheiten Transaktionen ausführen müssen, die sich über mehrere Modelle erstrecken, was die Komplexität erhöht, obwohl EF dies meiner Meinung nach ziemlich einfach macht.
  • Nach Absicht
    aufteilen Anstatt sich Gedanken über Schemata zu machen, sollten Sie die Modelle nach Absicht aufteilen. Wir haben also verschiedene Modelle für jede Anwendung, jedes Projekt, jedes Modul oder jeden Bildschirm, je nachdem, wie detailliert wir arbeiten möchten. Das Problem dabei ist, dass es bestimmte Tabellen gibt, die zwangsläufig in jedem Fall verwendet werden müssen, z. B. User oder AuditHistory. Fügen wir diese zu jedem Modell hinzu (verstößt meiner Meinung nach gegen DRY), oder befinden sich diese in einem separaten Modell, das von jedem Projekt verwendet wird?
  • Überhaupt nicht aufteilen - ein Riesenmodell
    Aus Sicht der Entwicklung ist dies offensichtlich einfach, aber aus meiner Forschung und meiner Intuition scheint es, als könnte es eine schreckliche Leistung erbringen, sowohl zur Entwurfszeit als auch zur Kompilierungszeit und möglicherweise zur Laufzeit.

Was ist die beste Vorgehensweise für die Verwendung von EF für eine so große Datenbank? Welche Strategien werden speziell beim Entwerfen von Modellen für dieses Volumen von DB-Objekten verwendet? Gibt es Optionen, bei denen ich nicht besser darüber nachdenke als oben?

Ist dies auch ein Problem in anderen ORMs wie NHibernate? Wenn ja, haben sie bessere Lösungen als EF gefunden?


"Transaktionen ausführen zu müssen, die sich über mehrere Modelle erstrecken, was die Komplexität erhöht." Hier nur eine Anmerkung, dass Sie Microsoft Distributed Transaction Coordinator aktivieren müssen. Sobald Sie das eingerichtet haben, sollte es einfach sein, das zu erreichen, wovon Sie sprechen.
Tjaart

@Tjaart danke. Ich habe MS DTC schon einmal verwendet, und obwohl es ziemlich einfach ist, erhöht es die Komplexität über eine einfache DB txn hinaus, so dass ich es nach Möglichkeit vermeiden möchte.
RationalGeek

2
4 Jahre später, was hast du entschieden und was würdest du jetzt empfehlen?
Rory

Antworten:


31

Persönlich habe ich versucht, ein großes Schema für alle meine Entitäten in einem ziemlich komplexen, aber kleinen Projekt (~ 300 Tabellen) zu erstellen. Wir hatten eine extrem normalisierte Datenbank (Normalisierung der 5. Form (ich sage das locker)) mit vielen "vielen zu vielen" Beziehungen und extremer Durchsetzung der referenziellen Integrität.

Wir haben auch eine "Single Instance per Request" -Strategie verwendet, von der ich auch nicht überzeugt bin, dass sie geholfen hat.

Bei einfachen, relativ flachen "explizit definierten" Auflistungen, Nachschlägen und Speichern war die Leistung im Allgemeinen akzeptabel. Aber als wir anfingen, tiefe Beziehungen zu knüpfen, schien die Leistung drastisch zu sinken. Im Vergleich zu einem gespeicherten Proc gab es in diesem Fall (natürlich) keinen Vergleich. Ich bin sicher, wir hätten die Codebasis hier und da optimieren können, um die Leistung zu verbessern. In diesem Fall mussten wir jedoch aus Zeitgründen die Leistung ohne Analyse steigern, und wir sind auf den gespeicherten Prozess zurückgefallen (haben ihn immer noch zugeordnet) durch EF (da EF stark typisierte Ergebnisse lieferte), brauchten wir das nur als Rückfall in einigen Bereichen. Als wir die gesamte Datenbank durchlaufen mussten, um eine Sammlung zu erstellen (mit .include ()), verschlechterte sich die Leistung merklich, aber vielleicht haben wir zu viel verlangt.

Aus meiner Erfahrung heraus würde ich empfehlen, einen separaten .edmx pro Intent zu erstellen. Generieren Sie nur das, was Sie verwenden, basierend auf dem Umfang dieses Bedarfs. Möglicherweise verfügen Sie über kleinere EDMX-Dateien für bestimmte Aufgaben und einige größere, bei denen Sie komplexe Beziehungen durchlaufen müssen, um Objekte zu erstellen. Ich bin mir nicht sicher, wo dieser magische Ort ist, aber ich bin mir sicher, dass es einen gibt ... lol ...

Mal ehrlich, abgesehen von ein paar Fallstricken, die wir gesehen haben (komplexes Überqueren), hat der riesige .edmx aus einer "funktionierenden" Perspektive gut funktioniert. Aber Sie müssen auf die "Korrektur" -Magie achten, die der Kontext hinter den Kulissen ausführt, wenn Sie ihn nicht explizit deaktivieren. Neben der Synchronisierung der .edmx-Datei, wenn Änderungen an der Datenbank vorgenommen wurden, war es manchmal einfacher, die gesamte Oberfläche zu bereinigen und die Entitäten neu zu erstellen. Dies dauerte ungefähr 3 Minuten, sodass es keine große Sache war.

Dies war alles mit EntityFramework 4.1. Ich wäre sehr daran interessiert, auch von Ihrer Endauswahl und Ihrer Erfahrung zu hören.

Und was deine Frage zu nHibernate angeht, das ist meiner Meinung nach eine Frage der Würmer, du wirst auf beiden Seiten des Zauns bellen ... Ich höre eine Menge Leute, die EF schlagen, um zu zerschlagen, ohne durch das zu arbeiten Herausforderungen und Verständnis der Nuancen, die EF selbst eigen sind. Obwohl ich nHibernate in der Produktion noch nie verwendet habe, erhalten Sie im Allgemeinen jedoch eine genauere Kontrolle, wenn Sie manuell und explizit Dinge wie Zuordnungen erstellen müssen Ich kann Drag & Drop, Generieren und Starten von CRUDs und Abfragen mit LINQ. Ich könnte einen Mist über die Granularität machen.

Ich hoffe das hilft.


1
Zu Ihrer Information: Es gibt ein NHibernate-Zuordnungsdienstprogramm, mit dem diese Zuordnungen SEHR einfach und automatisiert sind.
Ganders

@ganders - Hat es eine Benutzeroberfläche und wie ist es IDE-Integration? Ich gehe davon aus, dass Sie es auf eine Datenquelle verweisen und es die referenzielle Integrität und Objektdurchquerung respektiert und die Zuordnungsobjekte erstellt.
Hanzolo

1
Ja, das tut es (GUI). Ich hatte bisher keine Probleme damit. Verwendet es auf 4 oder 5 verschiedenen Projekten / Websites. Hinweis: Ich verwende es mit dem Fluent NHibernate, der das Mapping in c # -Code und nicht in config / xml-Dateien durchführt. Hier ist ein Link: nmg.codeplex.com
ganders

13

Lassen Sie mich mit einer einfachen Erläuterung beginnen: Ich habe keine Erfahrung mit einer so großen Datenbank, sodass der Rest meiner Antwort nicht auf dem Beispiel der realen Welt basiert.

Sie haben also eine BIG-Datenbank und möchten diese mit ORM / EF verwenden. Ich würde mit der zweiten Wahl gehen. Hier ist meine einfache Erklärung, warum:

  • Mapping erhöht die Komplexität. Es besteht keine Notwendigkeit, die Komplexität von Entitäten zu erhöhen, die Ihre aktuelle Anwendung / Ihr aktuelles Projekt / Ihr aktuelles Modul niemals benötigen. Machen Sie die Granularität jedoch nicht zu niedrig. Ein separater Mapping-Satz pro Bildschirm hilft Ihnen auch nicht weiter.
  • Sie möchten eine Arbeitseinheit erreichen. Sie sollten in der Lage sein anzugeben, welche Tabellen das Modul in den meisten Fällen benötigt (nicht in allen Fällen erforderlich). Wenn Sie diese Tabellen in einen einzelnen Zuordnungssatz einfügen, können Sie das Lesen und die Datenänderung durch eine einzelne Kontextinstanz handhaben - das sollte Ihr endgültiges Ziel sein.
  • Ich bin mir nicht sicher, was genau Sie mit Modell meinen, aber selbst mit unterschiedlichen Mapping-Sets können Sie Klassen zwischen Mapping-Sets mit denselben Entitätstypen teilen. Wenn Sie also die Benutzertabelle in zwei Modulen verwenden, benötigen Sie nicht zwei Benutzerklassen, um dasselbe darzustellen. Sie können weiterhin eine einzelne Tabelle verwenden und im Falle einer Code-Zuordnung (auch als Code-First bezeichnet) die Zuordnung sogar einmal definieren und in mehrere Zuordnungssätze laden, sodass das DRY-Prinzip nicht verletzt wird, der Code-First-Ansatz jedoch weitere Einschränkungen aufweist zu Ansichten und gespeicherten Prozeduren. EDMX erschwert dies. Sie können weiterhin Klassen wiederverwenden, die Zuordnung ist jedoch nicht möglich.
  • Was ist mit modulübergreifenden Abfragen? Diese Abfragen können vorkommen, aber um ehrlich zu sein, muss nicht alles von EF bearbeitet werden. Sie können EF für häufig vorkommende Fälle nutzen, um den regulären Datenzugriff zu vereinfachen. Wenn Sie jedoch eine spezielle Abfrage benötigen, die Tabellen aus 5 verschiedenen Modulen verknüpft, können Sie sie einfach direkt ausführen oder in eine gespeicherte Prozedur einbinden. Ein 100% iger Ersatz des nativen Datenzugriffs kann schwierig, komplex und kontraproduktiv sein.
  • Der letzte Punkt ist einfach praktisch: Ich glaube nicht, dass VS Tooling bereit ist, mit so vielen Objekten zu arbeiten - nicht im Designer, nicht einmal mit dem Importieren von Werkzeugen. Ich habe in VS2008 mit herkömmlichen Datenzugriffs- und SQL-Datenbankprojekten an sehr großen Datenbanken gearbeitet - die Benutzererfahrung mit einem komplexen Projekt war sehr schlecht. Sie müssen die Anzahl der verwendeten Tabellen niedrig halten - die Obergrenze für Designer sollte zwischen 100 und 200 liegen, aber selbst 100 Tabellen, die von einem einzelnen Kontext (Mapping-Set) verarbeitet werden, scheinen für eine Klasse zu viel Verantwortung zu übernehmen (vorausgesetzt, Sie haben 100 Set-Eigenschaften) Kontext belichtet - es sieht nicht nach einem guten Design aus).

4

Ich würde sagen, dass Sie diese Art von Frage aus technischer Sicht nicht entscheiden können. Ich würde empfehlen, dass Sie Ihre Architektur basierend auf Ihren Anwendungsfällen (User Stories usw.) erstellen. Finden Sie zuerst Ihre Geschäftsobjekte. Ein Entitätsobjekt ist nicht standardmäßig ein Geschäftsobjekt. In der Regel haben Sie ein Geschäftsobjekt vor den Entitätsobjekten. Dann können Sie schrittweise entscheiden, was Sie wirklich benötigen, basierend auf den Benutzeranforderungen.

"Ein guter Architekt maximiert die Anzahl der nicht getroffenen Entscheidungen." Robert C. Martin

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


3

Ich benutze einen hybriden Ansatz - OLTP-Daten werden von EF verarbeitet, während umfangreiche Vorgänge wie Batch-Einfügungen, Massenaktualisierungen, Berichtsabfragen usw. von Stored Procs verarbeitet werden. Dies erleichtert auch den Migrationspfad, wenn Sie nicht alle Daten auf einmal neu schreiben.


Dies scheint eine gute Strategie zu sein, befasst sich jedoch nicht wirklich mit der Frage, wie Entitäten zwischen verschiedenen EF-Modellen aufgeteilt werden können. Haben Sie alle Entitäten in einem Modell oder teilen und erobern Sie auf irgendeine Weise?
RationalGeek

1
Wenn die OLTP-Leistung mit dem Gesamtmodellansatz ausreicht, gehen Sie damit um. Sie können es später jederzeit auflösen, wenn Sie müssen. Am schnellsten und agilsten ist es jedoch, das Ganze zu laden. Möglicherweise benötigen Sie nie die Leistungsverbesserungen, die Sie durch das Aufteilen erzielen. Verschwenden Sie also Zeit und machen Sie Ihr System ohne Grund komplizierter. Dann stellt sich die Frage, an welches Modell Sie eine neue Tabelle / Entität kleben würden, wenn Sie sich für eine Erweiterung entscheiden. Und was passiert, wenn Sie ein Update für mehrere Modelle ausführen müssen? Sparen Sie sich die Kopfschmerzen, es sei denn, Sie haben wirklich keine Alternative.
Nik

Ich habe vergessen zu erwähnen, dass Sie Ihre Leistung beim Zugriff auf Ihre Daten jederzeit optimieren können. Schauen Sie sich die Optionen zum langsamen Laden und die von Ihnen eingebrachten untergeordneten Entitäten an. Ich sehe keinen Grund, warum sich ein vollständiges Modell schlechter verhält als ein kleineres, wenn Sie keine massiven Objektbäume laden.
Nik

Ich würde sagen, massive Objektbäume und eine normalisierte Datenstruktur gehen Hand in Hand, wenn es um große Schemas geht
hanzolo

Sie steuern, wie wenig oder wie viel Sie das Objektdiagramm sättigen möchten.
Nik
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.