Was sind die Nachteile, wenn ProxyCreationEnabled für CTP5 des EF-Codes zuerst deaktiviert wird?

82

Der einzige Weg, wie mein WCF-Dienst Klassen von einem Code-First-Modell zurückgeben kann, besteht ProxyCreationEnabledarin false, den folgenden Code zu verwenden.

((IObjectContextAdapter)MyDb).ObjectContext.ContextOptions.ProxyCreationEnable = false;

Was sind die negativen Folgen davon? Ein Vorteil ist, dass ich diese dynamischen Typen zumindest serialisieren kann, damit sie mit WCF über das Kabel gesendet werden können.

Ralph Shillington
quelle

Antworten:

71

Dynamische Proxys werden für die Änderungsverfolgung und das verzögerte Laden verwendet. Wenn WCF versucht, ein Objekt zu serialisieren, wird der zugehörige Kontext normalerweise geschlossen und entsorgt, aber die Serialisierung der Navigationseigenschaften löst automatisch ein verzögertes Laden aus (bei geschlossenem Kontext) => Ausnahme.

Wenn Sie das verzögerte Laden deaktivieren, müssen Sie für alle Navigationseigenschaften, die Sie verwenden möchten, eifrig laden (In ObjectQuery einschließen). Das Verfolgen von Änderungen funktioniert nicht über WCF, sondern nur zum Ändern von Entitäten, die an ObjectContext angehängt sind.

Ladislav Mrnka
quelle
7
Gibt es einen Leistungsvorteil beim Deaktivieren von ProxyCreationEnabled? Ich greife häufig nach einer DbContext-Instanz, um beispielsweise einen Lesevorgang mit eifrigem Laden durchzuführen.
Chris Moschini
2
@ChrisMoschini "Wenn eine POCO-Entität keinen Änderungsverfolgungs-Proxy hat, werden Änderungen gefunden, indem der Inhalt Ihrer Entitäten mit einer Kopie eines zuvor gespeicherten Status verglichen wird. Dieser gründliche Vergleich wird zu einem langwierigen Prozess, wenn Sie viele Entitäten in Ihrem Kontext haben oder wenn Ihre Entitäten eine sehr große Anzahl von Eigenschaften haben, auch wenn sich seit dem letzten Vergleich keine geändert hat. " msdn.microsoft.com/en-us/library/hh949853(v=vs.113).aspx
Niklas Peter
74

Wenn diese Option aktiviert DbContext.Configuration.ProxyCreationEnabledist false, lädt DbContext keine untergeordneten Objekte für ein übergeordnetes Objekt, es sei denn, die IncludeMethode wird für das übergeordnete Objekt aufgerufen. Die Einstellung DbContext.Configuration.LazyLoadingEnabledauf trueoder falsehat keinen Einfluss auf das Verhalten.

Wenn diese Option aktiviert DbContext.Configuration.ProxyCreationEnabledist true, werden untergeordnete Objekte automatisch geladen, und der DbContext.Configuration.LazyLoadingEnabledWert steuert, wann untergeordnete Objekte geladen werden.

Aleksey Timkov
quelle
10

Wenn Sie EF verwenden, wird standardmäßig ein Proxy für Ihre Klasse erstellt. Eine Lösung kann darin bestehen, diese Zeile im Konstruktor Ihrer DbContext-Klasse hinzuzufügen. Ihr Datenmodell wurde von der DbContext-Klasse geerbt, sodass Sie Ihr Modell folgendermaßen bearbeiten können:

    public yourDataModelEntities()
        : base("name=yourDataModelEntities")
    {
        base.Configuration.ProxyCreationEnabled = false;
    }

Diese Klasse ist in deinem EF.edmxDann im yourmodel.Context.ttDannyourmodel.Context.cs

Vicente Zambrano
quelle
2
Dies ist keine Antwort, aber es hat mir trotzdem geholfen.
Akira Yamamoto
1
Haben Sie einen guten Vorschlag, wie Sie den Prozess des Einfügens in diese Zeile automatisieren können? Jedes Mal, wenn ich ein Modell neu erstelle, muss ich sicherlich vergessen, die Eigenschaft auf false zu setzen, und das kann Stunden dauern, bis jemand merkt, was daran falsch ist.
Konrad Viltersten
@konrad - Erstellt den Code in einer Teilklasse, damit er nicht überschrieben wird. öffentliche Teilklasse yourDataMoldelEntities ()
Mikee
@ Mikee Wirklich? Ich würde einige Probleme erwarten, weil der automatisch generierte Konstruktor mit dem von mir in der
Teilklasse
@konrad Sie haben die Teilklasse 'Typ' erstellt, um Ihnen die Möglichkeit zu geben, Ihren Code nicht überschreiben zu lassen
Mikee
6

(Verwenden von Visual Studio 2013 oder höher)

Um zu vermeiden, dass der Klassenkonstruktor in Ihrem EF-Modell jedes Mal bearbeitet wird, wenn Sie das Modell aus der Datenbank aktualisieren oder auf andere Weise die Neuerstellung des Codes auslösen, befindet sich der richtige Ort für die Änderung in der T4-Codedatei, für die Sie verantwortlich sind Erstellen des Modellcodes. Ich hatte vor einigen Jahren ein anderes Problem mit dynamischen Eigenschaften, als ich die zugrunde liegende Mechanik der tatsächlichen Erstellung der Klassen und Eigenschaften verstand. T4 !!! Was für ein Wunder das ist :-D Die T4-Syntax kann zunächst ein wenig einschüchternd sein, daher ist es ratsam, sich über die Syntax zu informieren. Es ist auch eine gute Idee, bei Änderungen SEHR konzentriert zu sein :-)

So! Wenn Sie in Ihr Modell schauen, haben Sie eine .tt-Datei unter Ihrer .edmx-Datei. Diese .tt (T4) -Datei ist das Skript, mit dem Ihre Modellklasse tatsächlich erstellt wird. Das Skript wird jedes Mal automatisch ausgeführt, wenn Sie Ihr Modell erstellen oder einige Änderungen im Modelleditor vornehmen.

Angenommen , Ihr Modelldeskriptor heißt Model1.edmx . Sie haben eine Datei mit dem Namen Model1.Context.tt in der Baumstruktur darunter. Sie sehen auch eine Model1.Context.cs- Datei. Dies ist offensichtlich die eigentliche Codedatei für Ihren Kontext. Diese Datei ist jedoch das Ergebnis der Ausführung der .tt-Skriptdatei ! Es wird vollständig dynamisch erstellt. Also keine Ahnung, es zu bearbeiten.

Öffnen Sie die .tt-Datei und Sie sehen etwas wie:

<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ include file="EF6.Utility.CS.ttinclude"#><#@
 output extension=".cs"#><#

const string inputFile = @"Model1.edmx";
var textTransform = DynamicTextTransformation.Create(this);
..
..

Etwa 50 Zeilen weiter unten wird der Konstruktorcode geskriptet.

using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
<#
if (container.FunctionImports.Any())
{
#>
using System.Data.Entity.Core.Objects;
using System.Linq;
<#
}
#>

<#=Accessibility.ForType(container)#> partial class <#=code.Escape(container)#> : DbContext
    {
        public <#=code.Escape(container)#>()
            : base("name=<#=container.Name#>")
        {
        base.Configuration.ProxyCreationEnabled = false;
    <#
    if (!loader.IsLazyLoadingEnabled(container))
    {
    #>
            this.Configuration.LazyLoadingEnabled = false;
    <#
    }

Ich habe die Eigenschaft hinzugefügt base.Configuration.ProxyCreationEnabled = false; , damit es die allererste Zeile im Konstruktor ist.

Speichern Sie Ihre Datei und öffnen Sie die Datei Model1.Context.cs, um den resultierenden Code anzuzeigen. Wenn Sie die Ausführung des Vorlagenskripts erzwingen möchten, wählen Sie das Menü aus

Erstellen - Transformieren Sie alle T4-Vorlagen

Es ist leicht zu erkennen, ob Sie einen Fehler in Ihrem T4-Code gemacht haben, da die CS-Datei entweder überhaupt nicht erstellt wird oder offensichtliche Fehler aufweist, wenn Sie sie im Editor öffnen.

Per Malmstedt
quelle
Wow - dies sollte wirklich die bevorzugte Lösung sein, da es das Problem an der Wurzel behebt. Bietet außerdem einen guten Hintergrund zur Beziehung der * .tt-Datei zur resultierenden * .cs-Datei.
Douglas Timms