web-dev-qa-db-ger.com

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

Könnte jemand einen Rat geben oder auf einige Blogs/Artikel verweisen, die bei dieser Entscheidung helfen könnten? Die Stellvertreter erscheinen mir sehr fremd und ich zögere, sie zu benutzen. Ich mag die Fähigkeit, Lazy Loading mithilfe von virtuellen 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 mit dem Kontext verbinden, wenn die Entitäten einen geänderten Status aufweisen. 

Wie dem auch sei, hier ist jetzt meine sehr begrenzte Liste von Vor- und Nachteilen, lassen Sie mich wissen, ob ich mit irgendetwas nicht hier bin. 

Pros

  • Beim 'Speichern' oder 'Aktualisieren' bekomme ich nahtlos die 'Übernehmen'-Änderungen.
  • Lazy-Loading-Konfiguration ist sehr einfach.

Nachteile

  • Nie zuvor wurden Proxies für meine Entitäten verwendet. Dies ist eine Änderung in der Vorgehensweise, die für mich und andere Teammitglieder nur unangenehm erscheint. 
  • Umständlich zum 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.
66
matt_dev

Wenn Sie in EF über dynamische Proxies sprechen, gibt es zwei verschiedene Arten, um zu unterscheiden:

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

Normalerweise kann ein Änderungsverfolgungs-Proxy auch als Proxy für das langsame Laden dienen. Das Gegenteil trifft nicht zu. Dies liegt daran, dass die Anforderungen für Änderungsnachverfolgungsproxys höher sind, insbesondere alle -Eigenschaften - auch die Skalareigenschaften - müssen virtual sein. Für das langsame Laden reicht es aus, dass die Navigationseigenschaften virtual sind.

Die Tatsache, dass ein Änderungsverfolgungsproxy immer auch das langsame Laden nutzen kann, ist der Hauptgrund, warum DbContext dieses Konfigurationsflag besitzt:

DbContext.Configuration.LazyLoadingEnabled

Dieses Flag ist standardmäßig true. Durch die Einstellung auf false wird das verzögerte Laden deaktiviert, auch wenn Proxys erstellt werden. Dies ist besonders wichtig, wenn Sie mit Change-Tracking-Proxys arbeiten, diese Proxys jedoch nicht für das langsame 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 eine Bedeutung, wenn Ihre Entitätsklassen die Voraussetzungen zum Erstellen von Änderungsverfolgungs- oder Lazy-Loading-Proxys erfüllen.

Nun kennen Sie den Zweck von dynamischen Proxy-Proxies. Warum sollte man dynamische Änderungsverfolgungs-Proxys verwenden?

Eigentlich ist mir der einzige Grund, aus dem ich weiß, performance. Dies ist jedoch ein sehr guter Grund. Beim Vergleich der auf Schnappschüssen basierenden Änderungsnachverfolgung mit der auf Proxy basierenden Änderungsnachverfolgung ist der Leistungsunterschied enorm - aus meinen Messungen ist ein Faktor von 50 bis 100 realistisch (aus einer Methode entnommen, die für eine Zeit von 10000 Entites mit einer auf Schnappschuss basierenden Änderungsnachverfolgung eine Zeit von 30 bis 60 Sekunden benötigte) Nachdem Sie alle Eigenschaften virtuell gemacht haben, um die Änderungsnachverfolgungsproxys zu aktivieren). Dies ist ein wichtiger Faktor, wenn Sie über eine Anwendung verfügen, die viele (beispielsweise mehr als 1000) Entitäten verarbeitet und ändert. In einer Webanwendung, in der möglicherweise nur Vorgänge zum Erstellen, Ändern und Löschen für einzelne Entitäten in einer Webanforderung ausgeführt werden, ist dieser Unterschied nicht so wichtig.

In fast allen Situationen können Sie eifrige oder explizite Ladevorgänge nutzen, um dasselbe Ziel zu erreichen, wenn Sie nicht mit Lazy-Loading-Proxys arbeiten möchten. Die Leistung für das Proxy-basierte Lazy Loading oder für das Nicht-Proxy-Explicite-Laden ist die gleiche, da beim Laden von Navigationseigenschaften grundsätzlich die gleiche Abfrage ausgeführt wird. Im ersten Fall führt der Proxy die Abfrage aus, im zweiten Fall den von Hand geschriebenen Code. So können Sie ohne träge Ladeproxys leben, ohne zu viel zu verlieren.

Wenn Sie möchten, dass eine vernünftige Leistung viele, viele Entitäten verarbeiten kann, gibt es keine Alternative zum Ändern der Nachverfolgungsproxys - abgesehen von der Verwendung von EntityObject abgeleiteten Entitäten in EF 4.0 (keine Option in EF 4.1, da dies bei Verwendung von DbContext verboten ist) oder wenn Entity Framework nicht verwendet wird überhaupt.

Bearbeiten (Mai 2012)

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

Aufgrund dieser Komplikationen bei der Verwendung von Änderungsverfolgungsproxys empfiehlt es sich, die snapshotbasierte Änderungsnachverfolgung standardmäßig zu verwenden und die Proxys (nach einigen Tests) nur in Situationen zu verwenden, in denen eine hohe Leistung erforderlich ist und sie sich als schneller erweisen als die auf einem Schnappschuss basierenden Tracking ändern.

101
Slauma

Für alle, die Entity Framework 5 verwenden, lesen Sie den Artikel Überlegungen zur Leistung . Sections 5 NoTracking Queries und 8 Loading Related Entities bietet Ihnen die Informationen, die Sie für eine fundierte Entscheidung benötigen. Prost.

15
duoct

Ich würde vorschlagen, KEINE Proxies zu verwenden. Die Erstellung eines dynamischen Proxy unterbricht oder erstellt Komplikationen für Komponenten, die von der Laufzeitprüfung abhängig sind.

Automapper löst beispielsweise zur Laufzeit einen Typenkonflikt/unerwarteten Typfehler aus, da Ihre Entitäten zur Laufzeit dynamisch generierte Proxy-Typen haben und nicht die Typen, die Sie beim Konfigurieren von Automapping übergeben haben.

2
Daffy Punk

Verwenden Sie Automapper 4.2.1. Neue Version enthält keine DynamicMap

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

Obwohl dynamische Proxys einige Nice-Features aufweisen, können sie in Wirklichkeit viele seltsame und obskure Fehler verursachen.

Zum Beispiel behielt a eine private Variable einer Entität in einer meiner Klassen (es implementierte einen Stapelprozess), und ich durchlief einige Millionen Datensätze, verarbeitete und fügte sie in Batches ein, wobei der Datenkontext nach jedem n-Datensatz neu erstellt wurde Reinigen Sie den Speicher. Obwohl ich die private Variable NIE verwendet habe, verknüpfte EF sie mit meinen neuen Objekten (es gab eine Referenz über eine Navigationseigenschaft), obwohl ich nur die Referenz-ID eingestellt habe. 

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

Ich bin daher der Meinung, dass Sie die Proxys global deaktivieren und in kleinen und enthaltenen Code-Elementen aktivieren sollten. Es ist sehr gefährlich und unmöglich, solche Probleme zu debuggen, insbesondere wenn Sie Codierungen für große Teams haben. 

Das Änderungs-Tracking ist Nizza, es könnte die Verwendung an einigen Stellen rechtfertigen. Das langsame Laden kann ein großes Problem in Bezug auf Leistung und Serialisierung sein, wenn Sie nicht wissen, was Sie tun. Ich bevorzuge immer eifrige oder explizite Ladevorgänge.

0
Chriss