Nie można usunąć obiektu, ponieważ nie znaleziono go w ObjectStateManager


114

Otrzymuję ten błąd „Nie można usunąć obiektu, ponieważ nie został znaleziony w ObjectStateManager”.

Mój kod to:

    protected MyEntities sqlEntities;

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

5
Przepraszamy, wystąpił problem w kodzie, że do pobrania i usunięcia rekordu został użyty inny obiekt datacontext.
Sami

Miałem taki błąd: var entity = new TEntity() { PK_ID = 23 }; sqlEntities.DeleteObject(entity);próbowałem utworzyć pozorowaną jednostkę z prawidłowo ustawioną PK, w nadziei, że Entity Framework wywoła DeleteObject w oparciu o PK
C. Tewalt

Odpowiedzi:


156

Oznacza to, że jednostka nie jest dołączona (nie została załadowana przez tę samą instancję kontekstu). Spróbuj tego:

protected MyEntities sqlEntities;

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

1
Dzięki Ladislav. Pomogło mi to, gdy miałem dwa konteksty podczas usuwania danych dziecka od rodzica - który został wywołany z innego kontekstu, poza TransactionScope. Przeniesiono wywołanie rodzicielskie do zakresu i tego samego kontekstu, a mój problem został rozwiązany.
dan richardson,

1
@Ladislav: Jeśli używam .Attach, pojawia się inny błąd: „Wiele instancji IEntityChangeTracker nie może odwoływać się do obiektu encji”. Czy to oznacza, że ​​istnieją już inne instancje obiektów, które uniemożliwiają usunięcie?
Matt

2
@Matt: Nie, to znaczy, że twój obiekt jest już dołączony do innego kontekstu. Nie można go dołączyć do dwóch jednocześnie. Do usunięcia encji należy użyć oryginalnego kontekstu.
Ladislav Mrnka

@Ladislav: Dziękuję, że pomogło mi to w dalszych poszukiwaniach - znalazłem pytanie, które wydaje się odpowiadać na to: Czy można sprawdzić, czy obiekt jest już dołączony do kontekstu danych w Entity Framework? . Masz rację, wydaje się, że to jest problem w moim przypadku. Dzięki za szybką odpowiedź!
Matt,

Dzięki za przypomnienie, załączyłem je, kiedy tylko aktualizowałem rekord, ale nie podczas usuwania rekordu.
pinmonkeyiii

60

Tylko małe wyjaśnienie odpowiedzi Ladislava Mrnki (która powinna być odpowiedzią zaakceptowaną).

Jeśli tak jak ja, masz kod w takim formacie:

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

.. to co chcesz zrobić:

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

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

Być może wydaje się to oczywiste, ale początkowo nie było dla mnie jasne, że konieczne jest określenie podmiotu, do którego należy się przywiązywać, a nie tylko kontekstu .


1
Używam tego podejścia i otrzymuję wyjątek: „Instrukcja aktualizacji, wstawiania lub usuwania sklepu wpłynęła na nieoczekiwaną liczbę wierszy (0). Jednostki mogły zostać zmodyfikowane lub usunięte od czasu załadowania jednostek. Odśwież wpisy ObjectStateManager”.
kat1330

11

Żeby rozpropagować wyjaśnienie Kjartan:

Miałem:

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

Problem polega na tym, że użyłem własnej metody (GetProject ()), aby pobrać encję (stąd użycie innego kontekstu do załadowania jednostki):

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

Jednym rozwiązaniem mogłoby być dołączenie załadowanej jednostki, jak twierdzi Kjartan, innym rozwiązaniem mogłoby być rozwiązanie moje, aby załadować jednostkę w tym samym kontekście:

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

Wiem, że to pytanie jest dość stare, ale żadne z powyższych nie zadziałało, ponieważ usuwałem rejestry z więcej niż jednej klasy / usługi, a każdy z nich tworzył własny kontekst połączenia z bazą danych.

Aby go rozwiązać, wysłałem pierwszy utworzony kontekst do pozostałych klas / usług, które mają uzyskać dostęp do bazy danych.

Na przykład, serviceAzamierzałem usunąć niektóre z jego rejestrów i wywołać serviceBi serviceCzrobić to samo z ich rejestrami.

Następnie usunąłbym moje rejestry serviceAi przekazał jako parametr kontekst utworzony na serviceAto serviceBi serviceC.


2

Możesz napisać ten kod:

var x=yourquery.FirstOrDefault(); 

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

1

Jeśli żadne z powyższych nie zadziałało, możesz wypróbować to rozwiązanie:

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


0

Powinieneś być pewien, że twój obiekt znajduje się na liście, z której próbujesz usunąć, powinieneś umieścić następujący warunek

if (context.entity.contains (twój obiekt))

usunąć to.

jeśli masz skomplikowany warunek równości , powinieneś zastąpić metodę równości w klasie encji, aby umieścić warunek równości, aby uzyskać właściwą drogę dla metody rozszerzenia „entity.contains”


0

Upewnij się, że model przekazywany do funkcji Remove (Entity) jest dokładnie taki sam, jak rekord bazy danych.

Czasami można przekazać model bez niektórych pól, takich jak Id lub Data. zachowaj je w @ html.Hiddenfor jeśli wysyłasz jako formularz.

Najlepszym sposobem jest przekazanie identyfikatora i pobranie jednostki za pomocą metody Find (Id) i przekazanie jej do Remove (Entity)

Mam nadzieję, że to komuś pomoże.


0

Mam ten problem i go rozwiązuję. Po prostu skopiuj poniższy kod:

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

0

W moim przypadku był jeden kontekst, ale dostałem encję z opcją „AsNoTracking”

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.