Об'єкт не можна видалити, оскільки його не було знайдено в 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);я намагався створити макет-об'єкт з його ПК встановленим правильно, сподіваючись, що Entity Framework зателефонує DeleteObject на основі ПК
— 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: Ні, це не означає, що ваш об’єкт вже приєднаний до іншого контексту. Його не можна приєднати до двох одночасно. Для видалення сутності слід використовувати вихідний контекст.
— Ладислав Мрнка

@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

11

Просто для коректного пояснення Kjartans:

Я мав:

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

Ви повинні бути впевнені, що ваш об’єкт існує у списку, з якого ви намагаєтесь видалити, ви повинні поставити наступну умову

if (context.entity.contains (ваш об’єкт))

видали це.

якщо у вас є складна умова рівності, вам слід перекрити рівний метод у класі сутності, щоб поставити свою умову рівності, щоб отримати правильний шлях для методу розширення "entit.contains"


0

Переконайтесь, що модель, що переходить у Remove (Entity), точно така ж, як і запис бази даних.

Іноді можна передавати модель за допомогою деяких полів, таких як Id або Date. збережіть їх у @ html.Hiddenfor, якщо ви публікуєте як форму.

Найкращим способом є передача ідентифікатора та отримання об'єкта за допомогою методу Find (Id) та передача його для видалення (Entity)

Сподіваюся, що це комусь допоможе.


0

Я отримав цю проблему і вирішую її. Просто скопіюйте код нижче:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.