Warum ist mein Entity Framework-Code Erste Proxy-Sammlung null und warum kann ich es nicht gesetzt?

StackOverflow https://stackoverflow.com/questions/4069563

Frage

Ich bin mit DbContext und haben zwei Klassen, deren Eigenschaften sind alle virtuell. Ich kann im Debugger sehen, dass ich ein Proxy-Objekt immer bin, wenn ich den Kontext abfragen. Allerdings ist eine Sammlung Eigenschaft immer noch null, wenn ich versuche, um es hinzuzufügen. Ich dachte, dass der Proxy würde diese Sammlung gewährleisten initialisiert.

Weil mein Poco Objekt außerhalb seines Datenkontextes verwendet werden, habe ich einen Scheck für die Sammlung null im Konstruktor sein und bei Bedarf zu erstellen:

public class DanceStyle
{
    public DanceStyle()
    {
        if (DanceEvents == null)
        {
            DanceEvents = new Collection<DanceEvent>();
        }
    }
    ...
    public virtual ICollection<DanceEvent> DanceEvents { get; set; }
}

Das funktioniert außerhalb des Datenkontext, aber wenn ich ein Objekt mit einer Abfrage abzurufen, obwohl der Test wahr ist, wenn ich versuche, es zu setzen, ich folgende Ausnahme erhalten: ‚Die Eigenschaft‚DanceEvents‘vom Typ‚DanceStyle_B6089AE40D178593955F1328A70EAA3D8F0F01DDE9F9FBD615F60A34F9178B94‘kann nicht sein, Set, da die Sammlung ist bereits auf eine EntityCollection. "

Ich kann es sehen, ist null und ich kann es nicht hinzufügen, aber weder kann ich es auf eine Sammlung, weil der Proxy sagt es bereits gesetzt ist. Deshalb kann ich es nicht verwenden. Ich bin verwirrt.

Hier ist die DanceEvent Klasse:

public class DanceEvent
{
    public DanceEvent()
    {
        if (DanceStyles == null)
        {
            DanceStyles = new Collection<DanceStyle>();
        }
    }
    ...
    public virtual ICollection<DanceStyle> DanceStyles { get; set; }
}

Ich habe die anderen Mehrwert-Type-Eigenschaften aus dem obigen Code weggelassen. Ich habe keine andere Zuordnungen für die Klassen im Zusammenhang Klasse.

War es hilfreich?

Lösung 2

fand ich die Lösung für dieses Problem hier: Hinzufügen von Code Erste zu Sammlungen? Wie-Code zunächst mit Repositories verwenden?

entfernt I ‚virtuelle‘ aus allen Eigenschaften mit Ausnahme von Sammlungen und faul geladenen Objekte, die alle einheimischen Arten sind.

Aber ich verstehe immer noch nicht, wie Sie mit der Situation können am Ende, wo Sie eine Null-Sammlung haben, dass Sie nicht und haben keine Möglichkeit, es auf eine gültige Sammlung festlegen können.

Ich fand auch diese Antwort von Rowan Miller auf einem MSDN-Forum

  

Hallo,

     

Wenn Sie alle Ihre Eigenschaften virtuellen machen, dann wird EF-Proxy-Klassen zur Laufzeit generieren, dass ergibt sich aus Ihrer POCO eingestuft erlauben diese Proxies EF über Änderungen in Echtzeit, um herauszufinden, anstatt die ursprünglichen Werte des Objekts zu erfassen und dann scannen für Änderungen beim speichern (dies ist offensichtlich Vorteile Leistung und Speichernutzung hat aber der Unterschied wird vernachlässigbar sein, wenn Sie eine große Anzahl von Einheiten in dem Speicher geladen haben). Diese werden als ‚Change Tracking-Proxies‘ bekannt ist, wenn Sie Ihre Navigationseigenschaften virtuellen machen dann ein Proxy noch erzeugt wird, aber es ist viel einfacher und enthält nur einige Logik verzögertes Laden ausführen, wenn Sie eine Navigationseigenschaft zugreifen zu können.

     

Weil Ihr ursprünglicher Code wurde Change Tracking-Proxies zu erzeugen, wurde EF Ihre Sammlung Eigenschaft mit einem speziellen Sammlung Typ Hilfe ersetzt sie über Änderungen erfahren. Weil Sie versuchen, die Sammlung wieder zu einer einfachen Liste gesetzt im Konstruktor Sie die Ausnahme bekommen.

     

Wenn Sie Performance-Probleme sehen würde ich Terrence Vorschlag folgen und einfach entfernen ‚virtuelle‘ aus dem Nicht-Navigationseigenschaften.

     

~ Rowan

So scheint es, dass ich das Problem nur mit einem vollen ‚Change Tracking-Proxy‘, wenn alle meine Eigenschaften virtuell sind. Aber da, warum kann ich immer noch nicht die virtuelle Eigenschaft verwenden, auf dem Change Tracking-Proxy? Dieser Code sprengt auf Linie drei, weil ds2.DanceEvents null ist und nicht im Konstruktor gesetzt werden:

DanceStyle ds2 = ctx.DanceStyles.Where(ds => ds.DanceStyleId == 1).Single();
DanceEvent evt = CreateDanceEvent();
ds2.DanceEvents.Add(evt);

Ich bin immer noch verwirrt, obwohl mein Code funktioniert jetzt wegen der fix oben.

Andere Tipps

Wie Sie richtig in der Antwort auf Ihre eigene Frage, das Entfernen der „virtuellen“ Schlüsselwort aus der Sammlung Eigenschaften Werke, um das Problem zu beobachten, durch das Entity Framework die Verhinderung eines Wechsels Tracking-Proxy von der Erstellung. Dies ist jedoch keine Lösung für viele Menschen, weil Proxies Änderungsverfolgung wirklich praktisch sein kann, und kann helfen, Probleme zu verhindern, wenn Sie vergessen, Änderungen an den richtigen Stellen in Ihrem Code zu erkennen.

Ein besserer Ansatz wäre Ihre POCO Klassen zu modifizieren, so dass sie die Sammlung Eigenschaften in ihrem get-Accessor instanziiert, anstatt in dem Konstruktor. Hier ist Ihre POCO-Klasse, modifizierte Änderung zu ermöglichen, Proxy-Erstellung Tracking:

public class DanceEvent
{
    private ICollection<DanceStyle> _danceStyles;
    public virtual ICollection<DanceStyle> DanceStyles
    {
        get { return _danceStyles ?? (_danceStyles = new Collection<DanceStyle>()); }
        protected set { _danceStyles = value; }
    }
}

In dem obigen Code die Sammlung Objekt ist nicht mehr automatisch, sondern hat ein dahinter liegendes Feld. Es ist besser, wenn Sie die Setter geschützt und verhindert einen Code (außer dem Proxy) verlassen aus anschließend diese Eigenschaften zu modifizieren. Sie werden feststellen, dass der Konstruktor war nicht mehr notwendig und wurde entfernt.

Alte Frage ...

Poco-Klasse:

public partial class MyPOCO
{
    public MyPOCO()
    {
        this.MyPocoSub = new HashSet<MyPocoSub>();
    }

    //VIRTUAL
    public virtual ICollection<MyPocoSub> MyPocoSub { get; set; }
}

und Proxy-Code:

    public override ICollection<MyPocoSubSet> MyPocoSubSets
    {
        get
        {
            ICollection<MyPocoSubSet> myPocoSubSets = base.MyPocoSubSets;
            if (!this.ef_proxy_interceptorForMyPocoSubSets(this, myPocoSubSets))
            {
                return base.MyPocoSubSets;
            }
            return myPocoSubSets;
        }
        set
        {
            if (value != this.RelationshipManager.GetRelatedEnd("WindowsFormsApplication.Models.MyPocoSubSet_MyPOCO", "MyPocoSubSet_MyPOCO_Source"))
            {
                // EXCEPTION 
                throw new InvalidOperationException("The property 'MyPocoSubSets' on type 'MyPOCO_A78FCE6C6A890855C68B368B750864E3136B589F9023C7B1D90BF7C83FD291AC' cannot be set because the collection is already set to an EntityCollection.");
            }
            base.MyPocoSubSets = value;
        }
    }

Wie Sie die Ausnahme ausgelöst in Proxy-Klasse in ExtityFramework 5. sehen nach wie vor Dies bedeutet, dass das Verhalten existieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top