Sollte ich dynamische Proxys mit Entity Framework 4.1 und MVC3 aktivieren oder deaktivieren?

68

Könnte jemand Ratschläge geben oder auf Blogs / Artikel hinweisen, die bei dieser Entscheidung helfen könnten? Die Proxies scheinen mir sehr fremd zu sein und ich zögere, sie zu verwenden. Ich mag die Möglichkeit, Lazy Loading mithilfe virtueller Eigenschaften in meinem Modell zu steuern, aber das sind so ziemlich alle Vorteile, die ich sehen kann. Meine Anwendung ist eine einfache MVC-Webanwendung, und ich muss keine Hooks in den Kontext einbinden, wenn die Entitäten einen geänderten Status haben.

Wie auch immer, hier ist meine sehr begrenzte Liste von Vor- und Nachteilen. Lassen Sie mich wissen, ob ich mit irgendetwas davon nicht auf der Basis bin.

Vorteile

  • Bei "Speichern" oder "Aktualisieren" wird "Apply'Changes" nahtlos.
  • Lazy-Loading-Konfiguration ist sehr einfach.

Nachteile

  • Ich habe noch nie zuvor Proxies für meine Entitäten verwendet. Dies ist eine Änderung des Ansatzes, die für mich und andere Teammitglieder nur unangenehm erscheint.
  • Umständlich zu debuggen.
  • Benötigt zusätzlichen Code, wenn ich serialisieren / de-serialisieren möchte
  • Bei 'Speichern' oder 'Aktualisieren' muss der Proxy dasselbe Objekt sein, das aus dem Kontext abgerufen wurde.
matt_dev
quelle
7
+1 - Die Probleme mit der Serialisierung / Deserialisierung sind schmerzhaft!
StuartLC

Antworten:

103

Wenn Sie über dynamische Proxys in EF sprechen, müssen zwei verschiedene Typen unterschieden werden:

  • Proxies für faules Laden
  • Proxies für die Änderungsverfolgung

Normalerweise kann ein Änderungsverfolgungs-Proxy auch als Proxy für das verzögerte Laden dienen. Das Gegenteil ist nicht der Fall. Dies liegt daran, dass die Anforderungen an Änderungsverfolgungs-Proxys höher sind, insbesondere müssen alle Eigenschaften - auch die skalaren Eigenschaften - erfüllt sein virtual. Für ein verzögertes Laden reichen die Navigationseigenschaften aus virtual.

Die Tatsache, dass ein Änderungsverfolgungs-Proxy immer auch das verzögerte Laden ermöglicht, ist der Hauptgrund, warum der DbContext dieses Konfigurationsflag hat:

DbContext.Configuration.LazyLoadingEnabled

Dieses Flag ist standardmäßig wahr. Wenn Sie diese falseOption so einstellen , dass das verzögerte Laden deaktiviert wird, auch wenn Proxys erstellt werden. Dies ist besonders wichtig, wenn Sie mit Change-Tracking-Proxys arbeiten, diese Proxys jedoch nicht auch zum verzögerten Laden verwenden möchten.

Die Option ...

DbContext.Configuration.ProxyCreationEnabled

... deaktiviert die Proxy-Erstellung vollständig - auch für Änderungsverfolgung und verzögertes Laden.

Beide Flags haben nur dann eine Bedeutung, wenn Ihre Entitätsklassen die Anforderungen zum Erstellen von Änderungsverfolgungs- oder verzögerten Ladeproxys erfüllen.

Jetzt kennen Sie den Zweck des dynamischen verzögerten Ladens von Proxys. Warum sollte man also dynamische Änderungsverfolgungs-Proxys verwenden?

Der einzige Grund, den ich kenne, ist die Leistung . Dies ist jedoch ein sehr starker Grund. Beim Vergleich der auf Schnappschüssen basierenden Änderungsverfolgung mit der auf Proxys basierenden Änderungsverfolgung ist der Leistungsunterschied enorm - nach meinen Messungen ist ein Faktor von 50 bis 100 realistisch (entnommen aus einer Methode, die für 10000 Entites mit einer auf Schnappschüssen basierenden Änderungsverfolgung und 30 bis 60 Sekunden etwa eine Stunde benötigte nachdem alle Eigenschaften virtuell gemacht wurden, um Änderungsverfolgungs-Proxys zu aktivieren). Dies ist ein wichtiger Faktor, wenn Sie eine Anwendung haben, die viele (z. B. mehr als 1000) Entitäten verarbeitet und ändert. In einer Webanwendung, in der Sie möglicherweise nur Operationen zum Erstellen / Ändern / Löschen einzelner Entitäten in einer Webanforderung ausführen, ist dieser Unterschied nicht so wichtig.

In fast allen Situationen können Sie eifriges oder explizites Laden nutzen, um dasselbe Ziel zu erreichen, wenn Sie nicht mit Proxys zum verzögerten Laden arbeiten möchten. Die Leistung beim Proxy-basierten verzögerten Laden oder beim nicht-Proxy-basierten expliziten Laden ist dieselbe, da beim Laden der Navigationseigenschaften im Grunde dieselbe Abfrage erfolgt - im ersten Fall führt der Proxy die Abfrage durch, im zweiten Fall Ihren handgeschriebenen Code. Sie können also ohne verzögertes Laden von Proxys leben, ohne zu viel zu verlieren.

Wenn Sie jedoch eine angemessene Leistung für die Verarbeitung vieler, vieler Entitäten wünschen, gibt es keine Alternative zum Ändern von Tracking-Proxys - abgesehen von der Verwendung EntityObjectabgeleiteter Entitäten in EF 4.0 (keine Option in EF 4.1, da dies bei Verwendung verboten ist DbContext) oder der Verwendung von Entity Framework überhaupt nicht .

Bearbeiten (Mai 2012)

In der Zwischenzeit habe ich erfahren, dass es Situationen gibt, in denen Change-Tracking-Proxys im Vergleich zu Snapshot-basiertem Tracking nicht schneller oder sogar schlechter in der Leistung sind.

Aufgrund dieser Komplikationen bei der Verwendung von Änderungsverfolgungs-Proxys besteht die bevorzugte Methode darin, standardmäßig die auf Snapshots basierende Änderungsverfolgung zu verwenden und Proxys (nach einigen Tests) nur in Situationen sorgfältig zu verwenden, in denen eine hohe Leistung erforderlich ist und sich als schneller als auf Snapshots basierende erweist Änderungsverfolgung.

Slauma
quelle
1
@Slauma - Ich wusste nicht, dass Sie diese Konfigurationen im laufenden Betrieb ändern können, und dachte, dass sie nur verfügbar sind, wenn Domänendefinitionen erstellt werden. Mit if (DisableProxy) { context.Configuration.ProxyCreationEnabled = false; context.Configuration.LazyLoadingEnabled = false; }I konnte ich zulassen, dass diese dynamischen Proxys serialisiert werden können, ohne dass Zirkelverweisfehler auftreten. Vielen Dank! +1
Travis J
15

Lesen Sie für alle Benutzer von Entity Framework 5 unbedingt den Artikel zu Leistungsüberlegungen. Sections 5 NoTracking Queriesund 8 Loading Related Entitiesbietet die Informationen, die Sie benötigen, um eine fundierte Entscheidung zu treffen. Prost.

Duoct
quelle
2

Ich würde vorschlagen, KEINE Proxys zu verwenden. Die dynamische Proxy-Erstellung unterbricht oder verursacht Komplikationen für Komponenten, die von der Überprüfung des Laufzeit-Typs abhängig sind.

Automapper löst beispielsweise zur Laufzeit einen Typkonflikt / unerwarteten Typfehler aus, da Ihre Entitäten zur Laufzeit dynamisch Proxy-Typen generiert haben und nicht die Typen, die Sie bei der Konfiguration der automatischen Zuordnung übergeben haben.

CShark
quelle
1
Automapper war genau der Grund, warum ich mich damit befasst habe und die Kehrseite des potenziellen Umschaltens dynamischer Proxys.
Jim Wolff
Ich bin gewachsen, das ganze Konzept der dynamischen Proxys zu hassen. Erstens treten Probleme im Zusammenhang mit Proxys nur zur Laufzeit auf. Oft nur in der Produktion, wenn nicht offensichtliche Bedingungen erfüllt sind (die oft von Testern verrutschen). Zweitens handelt es sich um eine undichte Abstraktion, da beim Aufrufen von Code häufig das Vorhandensein und die besonderen Bedürfnisse von Proxys berücksichtigt werden müssen. Seitdem habe ich das gesamte Konzept aufgegeben, es ausgeschaltet und meine Entwürfe aktualisiert - und habe nie zurückgeschaut. Dynamische Proxies sollten in den Hinterkopf geschossen werden.
CShark
3
Freunde lassen Freunde keine dynamischen Proxys verwenden.
CShark
Am Ende habe ich es generell ausgeschaltet, um "Readonly" von der Datenbank abzurufen, und es beim Schreiben (für Changetracking) eingeschaltet gelassen, aber ich habe getestet, ob Changetracking ohne Proxys funktioniert, und es könnte der Einfachheit halber alles zusammen deaktivieren. Um andere Entwickler nicht in speziellen Szenarien zu stolpern, erstellen Sie nur Szenarien.
Jim Wolff
Sie scheinen in die richtige Richtung zu gehen. Ich habe das CQRS-Muster für meinen Datenzugriff auf ähnliche Weise verwendet, und es funktioniert hervorragend.
CShark
0

Obwohl dynamische Proxys einige nette Funktionen haben, können sie in Wirklichkeit viele seltsame und undurchsichtige Fehler verursachen.

Zum Beispiel hat eine private Variable einer Entität in einer meiner Klassen beibehalten (es wurde ein Stapelprozess implementiert) und ich habe einige Millionen Datensätze durchlaufen, sie verarbeitet und in Stapel eingefügt und den Datenkontext für alle n Datensätze neu erstellt Reinigen Sie den Speicher. Obwohl ich die private Variable NIE verwendet habe, hat EF sie mit meinen neuen Objekten verknüpft (es gab eine Referenz über eine Navigationseigenschaft), obwohl ich nur die Referenz-ID festgelegt habe.

Dies führte dazu, dass alle Objekte während der gesamten Laufzeit des Prozesses im Speicher blieben. Ich musste AsNoTracking verwenden und Proxys deaktivieren, damit der Prozess wie erwartet funktioniert und Speicher und Leistung wieder auf das normale Niveau zurückkehren. Beachten Sie, dass Proxys auch auf den Kontext verweisen, in dem sie erstellt wurden, und dass dadurch riesige Diagramme von Entitäten gespeichert werden können. Es ist fast unmöglich, sie zu debuggen

Ich bin daher der Meinung, dass Sie die Proxys global deaktivieren und in kleinen und enthaltenen Codeteilen aktivieren sollten. Es ist sehr gefährlich und unmöglich, solche Probleme zu debuggen, insbesondere wenn große Teams codieren.

Die Änderungsverfolgung ist nett, sie könnte die Verwendung an einigen Stellen rechtfertigen. Das verzögerte Laden kann ein großes Problem bei der Leistung und Serialisierung sein, es sei denn, Sie wissen, was Sie tun. Ich bevorzuge jederzeit eifriges oder explizites Laden.

Chriss
quelle
0

Verwenden Sie Automapper 4.2.1. Neue Version hat keine DynamicMap

var parents = parentsRepo.GetAll().ToList();
Mapper.CreateMap<Parent,ParentDto>();
var parentsDto = Mapper.DynamicMap<List<ParentDto>>(parents);
Madhusudhana Reddy Nadamala
quelle