Об'єкт не можна видалити, оскільки його не було знайдено в 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.