Das Objekt kann nicht gelöscht werden, da es nicht im ObjectStateManager gefunden wurde

114

Ich erhalte die Fehlermeldung "Das Objekt kann nicht gelöscht werden, da es nicht im ObjectStateManager gefunden wurde."

Mein Code lautet:

    protected MyEntities sqlEntities;

    public virtual void Delete(TEntity entity)
    {
        System.Type t = typeof(TEntity);
        sqlEntities.DeleteObject(entity);
        sqlEntities.SaveChanges();
    }
Sami
quelle
5
Es tut uns leid, dass im Code ein Problem aufgetreten ist, bei dem verschiedene Datenkontextobjekte zum Abrufen und Löschen von Datensätzen verwendet wurden.
Sami
Ich hatte einen Fehler wie diesen: var entity = new TEntity() { PK_ID = 23 }; sqlEntities.DeleteObject(entity);Ich habe versucht, eine Scheinentität mit korrekt eingestellter PK zu erstellen, in der Hoffnung, dass Entity Framework DeleteObject basierend auf der PK
C. Tewalt

Antworten:

156

Dies bedeutet, dass die Entität nicht angehängt ist (sie wurde nicht von derselben Kontextinstanz geladen). Versuche dies:

protected MyEntities sqlEntities;

public virtual void Delete(TEntity entity)
{
    sqlEntities.Attach(entity);
    sqlEntities.DeleteObject(entity);
    sqlEntities.SaveChanges();
}
Ladislav Mrnka
quelle
1
Danke Ladislav. Dies hat mir geholfen, als beim Löschen von untergeordneten Daten von einem Elternteil zwei Kontexte vor sich gingen - die aus einem anderen Kontext außerhalb eines TransactionScope aufgerufen wurden. Der übergeordnete Aufruf wurde in den Bereich und denselben Kontext verschoben, und mein Problem wurde gelöst.
Dan Richardson
1
@Ladislav: Wenn ich .Attach verwende, wird ein anderer Fehler angezeigt: "Ein Entitätsobjekt kann nicht von mehreren Instanzen von IEntityChangeTracker referenziert werden." Bedeutet dies, dass bereits andere Objektinstanzen aktiv sind, die das Löschen verhindern?
Matt
2
@Matt: Nein, es bedeutet, dass Ihr Objekt bereits an einen anderen Kontext angehängt ist. Es kann nicht gleichzeitig an zwei angehängt werden. Sie sollten den ursprünglichen Kontext verwenden, um die Entität zu löschen.
Ladislav Mrnka
@Ladislav: Vielen Dank, das hat mir geholfen, weiter zu suchen. Ich habe diese Frage gefunden, die zu beantworten scheint: Wie kann überprüft werden, ob ein Objekt bereits in Entity Framework an einen Datenkontext angehängt ist? . Sie haben Recht, dies scheint in meinem Fall das Problem zu sein. Danke für die schnelle Antwort!
Matt
Vielen Dank für die Erinnerung, ich hatte sie beim Aktualisieren eines Datensatzes angehängt, aber nicht beim Löschen eines Datensatzes.
Pinmonkeyiii
60

Nur eine kleine Klarstellung zur Antwort von Ladislav Mrnka (die akzeptierte Antwort sein sollte).

Wenn Sie wie ich Code in einem Format wie dem folgenden haben:

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

..dann das, was Sie tun möchten:

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

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

Vielleicht scheint dies offensichtlich zu sein, aber mir war anfangs nicht klar, dass es notwendig ist, die Entität anzugeben , auf die zugegriffen werden soll, und nicht nur den Kontext .

Kjartan
quelle
1
Ich verwende diesen Ansatz und erhalte die Ausnahme: "Die Anweisung zum Speichern, Einfügen oder Löschen des Speichers hat eine unerwartete Anzahl von Zeilen (0) beeinflusst. Entitäten wurden möglicherweise seit dem Laden von Entitäten geändert oder gelöscht. Aktualisieren Sie ObjectStateManager-Einträge."
Kat1330
11

Nur um Kjartans Erklärung zu erklären:

Ich hatte:

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

Das Problem ist, dass ich meine eigene Methode (GetProject ()) verwendet habe, um die Entität abzurufen (und daher einen anderen Kontext zum Laden der Entität verwendet habe):

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

Eine Lösung könnte darin bestehen, die geladene Entität wie von Kjartan angegeben anzuhängen, eine andere könnte meine Lösung sein, um die Entität im selben Kontext zu laden:

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;
        }
    }
esbenr
quelle
2

Ich weiß, dass diese Frage ziemlich alt ist, aber keine der oben genannten Fragen hat bei mir funktioniert, da ich Register aus mehr als einer Klasse / einem Dienst gelöscht habe und jede von ihnen ihren eigenen Datenbankverbindungskontext instanziiert hat.

Was ich getan habe, um es zu lösen, war, den ersten erstellten Kontext an die übrigen Klassen / Dienste zu senden, die auf die Datenbank zugreifen wollten.

Zum Beispiel wollte ich serviceAeinige seiner Register löschen und aufrufen serviceBund serviceCdasselbe mit ihren Registern tun.

Ich würde dann meine Register weiter löschen serviceAund als Parameter den Kontext übergeben, der auf dem serviceAto serviceBund erstellt wurde serviceC.

Terkhos
quelle
2

Sie können diesen Code schreiben:

var x=yourquery.FirstOrDefault(); 

sqlEntities.DeleteObject(x);
sqlEntities.SaveChanges();
mehdi
quelle
1

Falls keines der oben genannten Verfahren funktioniert hat, können Sie diese Lösung ausprobieren:

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

Ala 'Alnajjar
quelle
0

Sie sollten sicher sein, dass Ihr Objekt in der Liste vorhanden ist, aus der Sie entfernen möchten. Geben Sie die folgende Bedingung ein

if (context.entity.contains (Ihr Objekt))

entfernen Sie es.

Wenn Sie eine komplizierte Bedingung für die Gleichheit haben , sollten Sie die gleiche Methode in der Entitätsklasse überschreiben , um Ihre Bedingung für die Gleichheit festzulegen und den richtigen Weg für eine Erweiterungsmethode "entity.contains" zu finden.

Mohammad Ahmad Abdullah
quelle
0

Stellen Sie sicher, dass das an Remove (Entity) übergebene Modell genau mit dem Datenbankeintrag übereinstimmt.

Manchmal ist es möglich, das Modell ohne Felder wie ID oder Datum zu übergeben. Behalten Sie diese in @ html.Hiddenfor, wenn Sie als Formular posten.

Der beste Weg ist, die ID zu übergeben und die Entität mithilfe der Find (Id) -Methode abzurufen und diese an Remove (Entity) zu übergeben.

Hoffe das hilft jemandem.

Dheeraj Palagiri
quelle
0

Ich habe dieses Problem und löse es. Kopieren Sie einfach den folgenden Code:

sqlEntities.Attach(entity);
sqlEntities.Remove(entity);
sqlEntities.SaveChanges();
vahid sabet
quelle
0

In meinem Fall gab es einen Kontext, aber ich habe eine Entität mit der Option 'AsNoTracking' erhalten

vborutenko
quelle