Perché il mio Entity Framework Codice Prima raccolta procura nullo e il motivo per cui non può essere stata impostata?

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

Domanda

Sto usando DbContext e ho due classi le cui proprietà sono tutti virtuali. Posso vedere nel debugger che sto ottenendo un oggetto proxy quando interrogo il contesto. Tuttavia, una proprietà della raccolta è ancora nulla quando provo ad aggiungere ad essa. Ho pensato che il proxy dovrebbe garantire che la raccolta viene inizializzato.

Perché il mio oggetto Poco può essere utilizzato al di fuori del suo contesto di dati, ho aggiunto un controllo per la raccolta essere nullo nel costruttore e creare, se necessario:

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

che funziona al di fuori del contesto dati, ma se posso recuperare un oggetto utilizzando una query, anche se il test è vero, quando provo a impostare, vengo seguente eccezione: della struttura 'DanceEvents' sul tipo 'DanceStyle_B6089AE40D178593955F1328A70EAA3D8F0F01DDE9F9FBD615F60A34F9178B94' non può essere set, perché la collezione è già impostato su un EntityCollection. '

posso vedere è nullo e non posso aggiungere ad essa, ma non posso impostare una collezione perché il proxy dice che è già impostato. Perciò io non posso usarlo. Sono confuso.

Questa è la classe DanceEvent:

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

Ho omesso le altre proprietà tipo valore del codice precedente. Non ho altre mappature per le classi nella classe contesto.

È stato utile?

Soluzione 2

Ho trovato la soluzione a questo problema qui: Code First aggiungendo alle collezioni? Come utilizzare il codice Prima con i repository?

ho tolto 'virtuale' da tutte le proprietà ad eccezione di collezioni e oggetti caricati pigri, cioè, tutti i tipi nativi.

Ma io continuo a non capire come si può finire con la situazione in cui si dispone di una collezione nulla che non si può usare e non hanno modo di impostare una collezione valida.

Ho trovato anche questa risposta da Rowan Miller su un forum MSDN

  

Ciao,

     

Se si effettua tutte le proprietà virtuale allora EF genererà classi proxy in fase di esecuzione che deriva dalla vostra POCO classificati, questi proxy consentono EF per scoprire i cambiamenti in tempo reale, piuttosto che dover acquisire i valori originali del vostro oggetto e poi Rileva modifiche quando si salva (questo è, ovviamente, ha vantaggi di prestazioni e utilizzo della memoria, ma la differenza sarà trascurabile se non si dispone di un gran numero di entità caricati in memoria). Questi sono conosciuti come 'il rilevamento delle modifiche deleghe', se si fanno le proprietà di navigazione virtuale poi un proxy viene ancora generato, ma è molto più semplice e solo include una logica per eseguire il caricamento pigro quando si accede a una proprietà di navigazione.

     

Perché il vostro codice originale stava generando il rilevamento delle modifiche proxy, EF stava sostituendo la vostra proprietà collezione con uno speciale tipo di raccolta per aiutarla a scoprire i cambiamenti. Perché si cerca di impostare la parte posteriore di raccolta ad un elenco semplice nel costruttore si stanno ottenendo l'eccezione.

     

A meno che non si sta vedendo i problemi di prestazioni vorrei seguire il suggerimento di Terrence e basta rimuovere 'virtuale' dal proprietà non-navigazione.

     

~ Rowan

Quindi, sembra che ho solo il problema con un pieno 'delega il rilevamento delle modifiche' se tutte le mie proprietà sono virtuali. Ma dato che, per questo posso ancora utilizzare la proprietà virtuale sul proxy rilevamento delle modifiche? Questo codice fa saltare in aria sulla linea tre, perché ds2.DanceEvents è nullo e non possono essere impostati nel costruttore:

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

Sono ancora confuso, anche se il mio codice è ora al lavoro a causa della correzione sopra.

Altri suggerimenti

Come correttamente osservato nella risposta alla vostra domanda, eliminando la parola "virtuale" dalle proprietà collezione opere di tutto il problema, impedendo Entity Framework di creare un proxy rilevamento delle modifiche. Tuttavia, questa non è una soluzione per molte persone, perché il cambiamento di tracciamento proxy può essere davvero conveniente e può aiutare a prevenire problemi quando si dimentica di rilevare i cambiamenti al posto giusto nel codice.

Un approccio migliore sarebbe quello di modificare le classi POCO, in modo che essi istanziare le proprietà di raccolta nella loro accesso get, piuttosto che nel costruttore. Ecco la classe POCO, modificato per consentire il rilevamento delle modifiche creazione di proxy:

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

Nel codice sopra la struttura di raccolta non è più automatico, ma ha un campo di supporto. E 'meglio se si lascia il setter protetto, impedendo qualsiasi codice (diverso dal proxy) la successiva modifica queste proprietà. Si noterà che il costruttore non era più necessaria ed è stata rimossa.

Old domanda ...

class Poco:

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

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

e codice proxy:

    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;
        }
    }

Come si può vedere che un'eccezione sollevata in classe proxy nel ExtityFramework 5. Ciò significa che il comportamento esistono ancora.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top