2010-11-12 19 views
62

Mi chiedo il motivo per cui non esiste alcun metodo Detach sull'oggetto DbContext come se esistesse ObjectContext. Posso solo supporre che questa omissione sia stata intenzionale, ma ho difficoltà a capire perché. Devo essere in grado di staccare e riattaccare entità (per inserire la cache in un progetto ASP.NET, per esempio). Tuttavia, dal momento che non riesco a staccare un'entità, quando provo ad associare un'entità che era associata a un contesto precedente, ottengo l'eccezione "Un'entità dell'oggetto non può essere referenziata da più istanze di IEntityChangeTracker".Primo codice Entity Framework: metodo No Detach() su DbContext

Qual è la guida qui? Mi sto perdendo qualcosa?

+0

Qualcuno ha qualsiasi cosa da dire su: "Qual è la guida qui? Mi manca qualcosa?" Personalmente, mi interessa solo utilizzare Detach mentre cerco una soluzione per leggere un'entità dal contesto, prima di salvare l'istanza proveniente dall'interfaccia utente. Questo mi dà "Un oggetto con la stessa chiave esiste già in ObjectStateManager.L'ObjectStateManager non può tracciare più oggetti con la stessa chiave. " –

risposta

85

Per le persone che potrebbero inciampare su questa domanda, come di CTP5 è ora necessario scrivere

((IObjectContextAdapter)context).ObjectContext 

per arrivare a ObjectContext.

+1

+1 Anche tu È necessario fare riferimento a System.Data.Entity – Pandincus

+0

+1 Pulito, elegante, una fodera. Mi piace. Volevo anche gettare in che l'interfaccia si trova qui in particolare: System.Data.Entity.Infrastructure.IObjectContextAdapter e sì come Pandincus sottolineato devi anche fare un riferimento a System.Data.Entity. – dyslexicanaboko

38

DbContext utilizza un ObjectContext internamente e il team EF rendere questo disponibile come protetto proprietà solo nel caso in cui sia necessario discesa alle API di livello inferiore e suona come questo è il caso qui, in modo da poter utilizzare o esporre le funzionalità richieste da un DbContext derivato:

public class YourContext : DbContext 
{ 
    public void Detach(object entity) 
    { 
     ObjectContext.Detach(entity);    
    } 
} 

Quindi è possibile chiamare questo metodo dal controller di staccare un'entità.

In alternativa, si può cambiare di avere anche un'API più ricca:

public class YourContext : DbContext 
{ 
    public void ChangeObjectState(object entity, EntityState entityState) 
    { 
     ObjectContext.ObjectStateManager.ChangeObjectState(entity, entityState); 
    } 
} 

Ecco come DbContext assomiglia dai metadati:

public class DbContext : IDisposable 
{  
    protected System.Data.Objects.ObjectContext ObjectContext { get; } 
    ... 
} 
+0

@Stacker questa non è la risposta perché richiede il cast delineato nella risposta selezionata sopra, cioè il' DbContext' implementa 'IObjectContextAdapter' dandogli la proprietà' ObjectContext' che è non accessibile altrimenti Combinare le 2 risposte dà la risposta di @ splite sotto – eudaimos

+1

ChangeObjectState è piuttosto pigro, usa "algoritmo lineare con cast" che è ... Un po '... Sai ... Reeeeally male –

15

EF: CF 4.1 RC1 e EF: CF 4.1 RTW hanno lo stesso esplicitamente implementato IObjectContextAdapter:

public static class DbContextExtensions 
{ 
    public static void Detach(this System.Data.Entity.DbContext context, object entity) 
    { 
     ((System.Data.Entity.Infrastructure.IObjectContextAdapter)context).ObjectContext.Detach(entity); 
    } 
} 

Microsoft ha deciso "Staccare la tecnologia è troppo avanzata e deve essere nascosta". IMHO l'uomo che ha inventato questo dovrebbe essere girato - perché se aggiungi un'entità nuova di zecca, è altrimenti difficile rimuoverlo senza commutare le modifiche a db (puoi manipolarlo con DbEntityEntry ma questa è un'altra storia).

Edit 4 anni dopo:

Con EF6 (io in qualche modo saltati EF5 :)) non avete bisogno detach() più, siccome la rimozione di ingresso appena aggiunto non genera delete from [table] where [Id] = 0 come in EF4 - si può chiamare mySet.Remove(myFreshlyCreatedAndAddedEntity) e tutto andrà bene.

+0

shot? who ha bisogno di quella caratteristica comunque?: P – quetzalcoatl

+1

@quetzalcoatl: 'var context = ...; var poco = nuovo Poco(); context.Add (poco); context.Rimuovi (poco); '<--- genera un'eccezione perché devi DETERMINARLO, non rimuovere - ehi, staccare è nascosto ... –

+1

(5 minuti per la modifica andata, sry :)) A quel tempo ero così arrabbiato ... Quando stai facendo l'app di Windows, devi avere un modo per "cancellare la creazione di una nuova, probabilmente incompleta voce ma mantenere il contesto di UoW" ... Ci liberiamo di tutta EF btw e scriviamo il nostro ORM: C'è nessun modo per utilizzare il caricamento lazy (ho un mucchio di Fatture e non posso caricare ogni InvoiceItem in una query "where InvoiceId in (xxyy)" - Include doesnt funziona come ci aspettavamo), i repository più grandi sono sooooo pigri (lineari (!!! ricerca prima di ogni esecuzione, wtf ...), la creazione di proxy per oltre 100 tipi richiede troppo tempo e così via ... –

6

Io di solito estendere la classe base (eredita dalla DbContext) con la proprietà:

public class MyDbContext : DbContext 
{ 
    public ObjectContext ThisObjectContext 
    { 
     get 
     { 
      return ((IObjectContextAdapter)this).ObjectContext; 
     } 
    } 
} 

seguito è possibile utilizzare questa proprietà per varietà di cose utili ... come Staccare :)

Problemi correlati