L'oggetto non può essere eliminato perché non è stato trovato in ObjectStateManager


114

Ricevo questo errore "Impossibile eliminare l'oggetto perché non è stato trovato in ObjectStateManager."

Il mio codice è:

    protected MyEntities sqlEntities;

    public virtual void Delete(TEntity entity)
    {
        System.Type t = typeof(TEntity);
        sqlEntities.DeleteObject(entity);
        sqlEntities.SaveChanges();
    }

5
Spiacenti, si è verificato un problema nel codice per cui sono stati utilizzati diversi oggetti datacontext per recuperare ed eliminare il record.
Sami

Avevo un bug come questo: var entity = new TEntity() { PK_ID = 23 }; sqlEntities.DeleteObject(entity);stavo cercando di creare un'entità fittizia con il suo PK impostato correttamente, nella speranza che Entity Framework chiamasse DeleteObject basato sul PK
C. Tewalt

Risposte:


156

Significa che l'entità non è collegata (non è stata caricata dalla stessa istanza di contesto). Prova questo:

protected MyEntities sqlEntities;

public virtual void Delete(TEntity entity)
{
    sqlEntities.Attach(entity);
    sqlEntities.DeleteObject(entity);
    sqlEntities.SaveChanges();
}

1
Grazie Ladislav. Questo mi ha aiutato quando avevo due contesti in corso durante l'eliminazione dei dati figlio da un genitore, che è stato chiamato da un contesto diverso, al di fuori di un TransactionScope. Spostata la chiamata del genitore all'interno dell'ambito e nello stesso contesto e il mio problema è stato risolto.
dan richardson

1
@Ladislav: Se utilizzo .Attach, ricevo un errore diverso: "Non è possibile fare riferimento a un oggetto entità da più istanze di IEntityChangeTracker." Significa che esistono già altre istanze di oggetti attive che impediscono l'eliminazione?
Matt

2
@ Matt: No significa che il tuo oggetto è già collegato a un altro contesto. Non può essere collegato a due contemporaneamente. È necessario utilizzare il contesto originale per eliminare l'entità.
Ladislav Mrnka

@Ladislav: Grazie, questo mi ha aiutato a guardare oltre - Ho trovato questa domanda che sembra rispondere a come affrontarla: è possibile verificare se un oggetto è già collegato a un contesto dati in Entity Framework? . Hai ragione, questo sembra essere il problema nel mio caso. Grazie per la risposta rapida!
Matt

Grazie per il promemoria, l'avevo allegato quando aggiornavo un record, ma non quando stavo eliminando un record.
pinmonkeyiii

60

Solo un piccolo chiarimento sulla risposta di Ladislav Mrnka (che dovrebbe essere la risposta accettata).

Se come me, hai il codice in un formato come questo:

using (var context = new MyDataContext())
{
    context.MyTableEntity.Remove(EntytyToRemove);
    var nrOfObjectsChanged = context.SaveChanges();
}

..quindi questo è quello che vuoi fare:

using (var context = new MyDataContext())
{
    // Note: Attatch to the entity:
    context.MyTableEntity.Attach(EntityToRemove);

    context.MyTableEntity.Remove(EntityToRemove);
    var nrOfObjectsChanged = context.SaveChanges();
}

Forse questo sembra ovvio, ma inizialmente non mi era chiaro che fosse necessario specificare l' entità a cui attaccarsi, e non solo il contesto .


1
Uso questo approccio e ricevo un'eccezione: "L'istruzione di aggiornamento, inserimento o eliminazione del negozio ha interessato un numero imprevisto di righe (0). Le entità potrebbero essere state modificate o eliminate da quando le entità sono state caricate. Aggiorna le voci ObjectStateManager."
kat1330

11

Giusto per correggere la spiegazione di Kjartans:

Avevo:

public Project DeleteProject(int id)
    {
        using (var context = new Context())
        {
            var p = GetProject(id);
            context.Projects.Remove(p);
            context.SaveChanges();
            return p;
        }
    }

Il problema è che ho usato il mio metodo (GetProject ()) per ottenere l'entità (quindi utilizzando un altro contesto per caricare l'entità):

public Project GetProject(int id)
    {
        using (var context = new Context())
        {
            var project = context.Projects
                .Include(p => p.Reports.Select(q => q.Issues.Select(r => r.Profession)))
                .Include(p => p.Reports.Select(q => q.Issues.Select(r => r.Room)))
                .SingleOrDefault(x => x.Id == id);
            return project;      
        }
    }

Una soluzione potrebbe essere quella di collegare l'entità caricata come afferma Kjartan, un'altra potrebbe essere la mia soluzione, per caricare l'entità nello stesso contesto:

public Project DeleteProject(int id)
    {
        using (var context = new Context())
        {
            var p = context.Projects.SingleOrDefault(x => x.Id == id);
            if (p == null)
                return p;

            context.Projects.Remove(p);
            context.SaveChanges();
            return p;
        }
    }

2

So che questa domanda è piuttosto vecchia ma nessuna delle precedenti ha funzionato per me poiché stavo cancellando i registri da più di una classe / servizio e ognuno di essi creava un'istanza del proprio contesto di connessione al database.

Quello che ho fatto per risolverlo è stato inviare il primo contesto creato al resto delle classi / servizi che dovevano accedere al database.

Ad esempio, il mio serviceAstava per eliminare alcuni dei suoi registri e chiamare serviceBe serviceCfare lo stesso con i loro registri.

Vorrei quindi eliminare i miei registri su serviceAe passare come parametro il contesto creato sul serviceAper serviceBe serviceC.


2

Puoi scrivere questo codice:

var x=yourquery.FirstOrDefault(); 

sqlEntities.DeleteObject(x);
sqlEntities.SaveChanges();

1

Nel caso in cui nessuna delle soluzioni precedenti abbia funzionato, puoi provare questa soluzione:

context.Entry(yourObject).State = System.Data.Entity.EntityState.Deleted; context.SaveChanges();


0

Dovresti essere sicuro che il tuo oggetto sia presente nell'elenco da cui stai tentando di rimuovere, dovresti mettere la seguente condizione

if (context.entity.contains (il tuo oggetto))

rimuoverla.

se hai una condizione complicata per l'uguaglianza dovresti sovrascrivere il metodo equal nella classe entità per mettere la tua condizione per l'uguaglianza, per ottenere il modo giusto per un metodo di estensione "entity.contains"


0

Assicurati che il modello che passa a Remove (Entity) sia esattamente lo stesso del record del database.

A volte è possibile passare il modello senza alcuni campi come Id o Data. tienili in @ html.Hiddenfor se pubblichi come modulo.

Il modo migliore è passare l'ID e ottenere l'entità utilizzando il metodo Find (Id) e passarlo a Remove (Entity)

Spero che questo aiuti qualcuno.


0

Ho questo problema e lo risolvo. Basta copiare il codice sottostante:

sqlEntities.Attach(entity);
sqlEntities.Remove(entity);
sqlEntities.SaveChanges();

0

Nel mio caso c'era un contesto, ma ho ottenuto l'entità con l'opzione "AsNoTracking"

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.