Sollte eine ASP.NET MVC-Anwendung Entity Framework direkt als Modell verwenden?

22

Ich erstelle meine erste MVC-Anwendung in Visual Studio 2013 (MVC 5) und bin mir nicht sicher, wie ich mein Modell am besten einrichten kann.

Ich habe ein Entity-Framework-Modell mit Code-First aus einer vorhandenen Datenbank generiert. Mein erster Instinkt war, einige Zwischenklassen zu erstellen, die das von den Ansichten verwendete Modell darstellen und die mit den Entity-Framework-Klassen funktionieren.

Als ich die Zwischenklassen schrieb, stellte ich fest, dass ich viele Dinge, die die EF-Klassen bereits machten, meistens nur mit dem gelegentlichen privaten Setter neu implementierte oder von einem Datentyp in einen anderen übersetzte. Das schien also eine Verschwendung zu sein.

Ist die allgemeine Regel, die Entity-Framework-Klassen direkt als Modell für eine MVC-Anwendung zu verwenden? Oder gibt es einen Vorteil, den ich für den Aufbau dieser Zwischenklassen vermisse?

Mike D.
quelle
Wenn Sie Code-First verwendet haben, war keine Datenbank vorhanden, oder?
Isaac Kleinman
1
Mit EF 6.1+ können Sie ein Code-First-Modell aus einer vorhandenen Datenbank generieren. Siehe diesen MSDN-Artikel: msdn.microsoft.com/en-au/data/jj200620.aspx
Mike D.

Antworten:

23

In meinen Anwendungen habe ich die Dinge immer getrennt, mit verschiedenen Modellen für die Datenbank (Entity Framework) und MVC. Ich habe diese auch in verschiedene Projekte aufgeteilt:

  • Example.Entities - Enthält meine Entitäten für EF und den DB-Kontext für den Zugriff darauf.
  • Example.Models - enthält MVC-Modelle.
  • Example.Web - Webanwendung. Hängt von Example.Domain und Example.Models ab.

Anstatt wie bei den Domänenentitäten Verweise auf andere Objekte zu speichern, enthalten die MVC-Modelle IDs als Ganzzahlen.

Wenn eine GET-Anforderung für eine Seite eingeht, führt der MVC-Controller die Datenbankabfrage durch, die eine Entität zurückgibt. Ich habe "Converter" -Methoden geschrieben, die eine Domänenentität in ein MVC-Modell konvertieren. Es gibt andere Methoden, die das Gegenteil bewirken (von einem MVC-Modell zu einer Domänenentität). Das Modell wird dann an die Ansicht und damit an den Client übergeben.

Wenn eine POST-Anforderung eingeht, erhält der MVC-Controller ein MVC-Modell. Eine Konvertierungsmethode konvertiert dies in eine Domänenentität. Diese Methode führt auch Überprüfungen durch, die nicht als Attribute ausgedrückt werden können, und stellt sicher, dass die bereits vorhandene Domänenentität aktualisiert wird, anstatt eine neue zu erhalten. Die Methoden sehen normalerweise ungefähr so ​​aus:

public class PersonConverter
{
    public MyDatabaseContext _db;

    public PersonEntity Convert(PersonModel source)
    {
         PersonEntity destination = _db.People.Find(source.ID);

         if(destination == null)
             destination = new PersonEntity();

         destination.Name = source.Name;
         destination.Organisation = _db.Organisations.Find(source.OrganisationID);
         //etc

         return destination;
    }

    public PersonModel Convert(PersonEntity source)
    {
         PersonModel destination = new PersonModel()
         {
             Name = source.Name,
             OrganisationID = source.Organisation.ID,
             //etc
         };

         return destination;
    }
}

Mit diesen Methoden entferne ich die Vervielfältigung, die sonst in jedem Controller auftreten würde. Die Verwendung von Generika kann die Dinge noch weiter deduplizieren.

Diese Vorgehensweise bietet mehrere Vorteile:

  • Sie können ein Modell an eine bestimmte Ansicht oder Aktion anpassen. Angenommen, Sie haben ein Anmeldeformular für eine Person, die bei der Übermittlung viele verschiedene Entitäten erstellt (Person, Organisation, Adresse). Ohne separate MVC-Modelle wird dies sehr schwierig.
  • Wenn ich mehr Informationen an die Ansicht übergeben muss, als sonst nur in der Entität verfügbar wären, oder wenn ich zwei Entitäten zu einem einzigen Modell kombiniere, werden meine wertvollen Datenbankmodelle nie berührt.
  • Wenn Sie ein MVC-Modell jemals als JSON oder XML serialisieren, wird nur das unmittelbare Modell serialisiert, nicht jede andere Entität, die mit diesem Modell verknüpft ist.
Jack Scott
quelle
Gute Antwort, würde die Verwendung von ValueInjector oder etwas Ähnlichem empfehlen (ich persönlich hasste automapper), anstatt Eigenschaften manuell von einer Klasse zur anderen zuzuordnen.
Rocklan
1
Anstatt eine separate Antwort hinzuzufügen, möchte ich hier nur darauf hinweisen, dass in DDD-Verfahren Ihre "Konverter" und separaten Modelle für die Ansicht als Teil des Application Service Layer betrachtet werden. Grundsätzlich ermöglicht es Ihrem Domain-Modell, so komplex wie nötig zu sein und diese Komplexität vor der Anwendung zu verbergen. Es schützt die Anwendung auch davor, aufgrund einer Änderung des Domänenmodells geändert werden zu müssen. Die ASL übernimmt die Übersetzung.
Michael Brown
Sie rufen also jedes Modell in Ihrem PersonModel (dh das Organisationsobjekt) auf, um die Informationen zu diesem Modell abzurufen. Angenommen, Sie haben ein Formular zum Aktualisieren der Person und der Organisationsinformationen. Wünschen Sie einen zusätzlichen Anruf, wenn Sie die Organisation aktualisieren? Ich verwende gespeicherte Prozeduren. Kann ich also nicht alle Attribute des Modells und alle Attribute des enthaltenen Modells gleichzeitig senden?
Leuchtende
1
Wie würden Sie mit der Zuordnung einer Sammlung umgehen? Das scheint in EF6 viel komplizierter gewesen zu sein, da Sie nicht mehr nur eine neue Liste von Entitäten mit den Aktualisierungen erstellen können, da hierdurch einfach alles neu erstellt wird ...
Gerard Wilkinson
2
Anstatt eigene Konvertierungsklassen zu schreiben, würde ich empfehlen, die Automapper- Bibliothek zu verwenden, die zur Behebung dieses Problems geschrieben wurde. Es ist seit 2014 sehr gereift!
BenSmith
6

Ich würde sagen, es hängt wirklich von Ihrer Anwendung ab. Geht es nur um CRUD ohne Geschäftslogik? Dann würde ich EF-Modelle direkt in meinen Ansichten verwenden.

In den meisten Fällen handelt es sich zumindest um eine Geschäftslogik, und eine Schicht zwischen den Daten- / EF-Modellen und der Ansicht ist möglicherweise eine gute Idee. In diesem Fall ist es möglicherweise angebracht, "CQRS-lite" (siehe unten) auszuführen und verschiedene Modelle für den Controller und für den Ausgang zu verwenden. Meistens sind die gelesenen Modelle viel "fetter" als die Schreibmodelle ...

Wenn die Anwendung jedoch viel Geschäftslogik enthält und / oder viel skaliert werden muss, würde ich zumindest den Kern mithilfe von CQRS (Command Query Responsibility Segregation), DDD (Domain Driven Design) und möglicherweise Event Sourcing implementieren. Dann könnte EF als Lesemodellfassade verwendet werden.

Denken Sie auch daran, dass Sie sich nicht für die gesamte Anwendung an eine Strategie / ein Muster halten müssen. Einige Bereiche sind möglicherweise reine CRUD-Bereiche, andere enthalten möglicherweise eine Menge Geschäftslogik.

jhdrn
quelle