Невозможно удалить объект, поскольку он не был найден в ObjectStateManager.


114

Я получаю сообщение об ошибке «Объект не может быть удален, потому что он не найден в ObjectStateManager».

Мой код:

    protected MyEntities sqlEntities;

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

5
К сожалению, в коде возникла проблема, связанная с тем, что для получения и удаления записи использовались разные объекты контекста данных.
Сами

У меня была такая ошибка: var entity = new TEntity() { PK_ID = 23 }; sqlEntities.DeleteObject(entity);я пытался создать фиктивный объект с правильной установкой PK в надежде, что Entity Framework вызовет DeleteObject на основе PK
C. Tewalt

Ответы:


156

Это означает, что объект не прикреплен (он не был загружен тем же экземпляром контекста). Попробуй это:

protected MyEntities sqlEntities;

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

1
Спасибо, Ладислав. Это помогло мне, когда у меня было два контекста при удалении дочерних данных из родительского, которые вызывались из другого контекста, за пределами TransactionScope. Перенес родительский вызов внутрь области видимости и в том же контексте, и моя проблема была решена.
Дэн Ричардсон

1
@Ladislav: Если я использую .Attach, я получаю другую ошибку: «На объект сущности не могут ссылаться несколько экземпляров IEntityChangeTracker». Означает ли это, что уже существуют другие живые экземпляры объектов, препятствующие удалению?
Мэтт

2
@Matt: Нет, это означает, что ваш объект уже привязан к другому контексту. Его нельзя прикрепить к двум одновременно. Для удаления объекта следует использовать исходный контекст.
Ладислав Мрнка 06

@Ladislav: Спасибо, это помогло мне поискать дальше - я нашел этот вопрос, который, кажется, дает ответ на его решение: можно ли проверить, прикреплен ли объект к контексту данных в Entity Framework? , Вы правы, похоже, это проблема в моем случае. Спасибо за быстрый ответ!
Мэтт

Спасибо за напоминание, я прикрепил его, когда просто обновлял запись, но не когда удалял запись.
pinmonkeyiii

60

Просто небольшое пояснение к ответу Ладислава Мрнки (который должен быть принятым ответом).

Если, как и я, у вас есть код в таком формате:

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

... тогда это то, что вы хотите сделать:

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

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

Возможно, это кажется очевидным, но мне изначально не было ясно, что необходимо указать сущность, к которой нужно привязаться, а не только контекст .


1
Я использую этот подход и получаю исключение: «Операторы обновления, вставки или удаления хранилища повлияли на неожиданное количество строк (0). Сущности могли быть изменены или удалены после загрузки объектов. Обновить записи ObjectStateManager».
kat1330 04

11

Просто чтобы перейти к объяснению Кьяртана:

Я имел:

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

Проблема в том, что я использовал свой собственный метод (GetProject ()) для получения объекта (следовательно, использовал другой контекст для загрузки объекта):

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

Одним из решений может быть присоединение загруженного объекта, как утверждает Кьяртан, другим может быть мое решение для загрузки объекта в том же контексте:

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

Я знаю, что этот вопрос довольно старый, но ничего из вышеперечисленного не помогло мне, так как я удалял регистры из более чем одного класса / службы, и каждый из них создавал экземпляр своего собственного контекста подключения к базе данных.

Чтобы решить эту проблему, я отправил первый созданный контекст остальным классам / службам, которые собирались получить доступ к базе данных.

Например, я serviceAсобирался удалить некоторые из своих регистров и вызвать serviceBиserviceC сделать то же самое с их регистрами.

Затем я бы удалил свои регистры serviceAи передал в качестве параметра контекст, созданный serviceAдля serviceBи serviceC.


2

Вы можете написать этот код:

var x=yourquery.FirstOrDefault(); 

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

1

Если ничего из вышеперечисленного не помогло, вы можете попробовать следующее решение:

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


0

Вы должны быть уверены, что ваш объект существует в списке, из которого вы пытаетесь удалить, вы должны поставить следующее условие

если (context.entity.contains (ваш объект))

убери это.

если у вас есть сложное условие равенства, вы должны переопределить метод равенства в классе сущности, чтобы поставить условие равенства, чтобы получить правильный способ для метода расширения entity.contains


0

Убедитесь, что модель, передаваемая в Remove (Entity), точно такая же, как и запись в базе данных.

Иногда можно передать модель без некоторых полей, таких как Id или Date. сохраните их в @ html.Hiddenfor, если вы публикуете как форму.

Лучший способ - передать идентификатор и получить объект с помощью метода Find (Id) и передать его в Remove (Entity).

Надеюсь, это кому-то поможет.


0

Я получил эту проблему и решил ее. Просто скопируйте приведенный ниже код:

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

0

В моем случае был один контекст, но я получил объект с опцией AsNoTracking

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.