Объект нельзя удалить, поскольку он не был найден в ObjectStateManager в структуре сущности 5

Я пытаюсь удалить объект, используя EntityFramework 5, но я получаю эту ошибку. Объект нельзя удалить, поскольку он не был найден в ObjectStateManager
Я использую метод Remove(), поскольку DeleteObject() отсутствует в EF5. Может ли кто-нибудь помочь, что мне не хватает?

Это не работает для удаления

localDb.Customers.Remove(new Customer() { CustomerId = id });
                localDb.SaveChanges();

Еще одна вещь, которую я пробовал из msdn, чтобы изменить состояние на Deleted. Но здесь он дает ошибку, говоря, что все поля должны присутствовать. Нужно ли получить полную запись, а затем удалить?

var customer = new Customer(){ CustomerId = id };
                localDb.Customers.Attach(customer);

                localDb.Entry(customer).State = EntityState.Deleted;
                localDb.SaveChanges();

Любые входы?

Ответ 1

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

Если вы хотите сделать это за один удар, ваша вторая версия с Attach будет работать - пока объект еще не загружен в контекст.

Ошибка, которую вы получаете, вызвана проверкой EF, которая выполняется перед записью любой базы данных.

Вы можете временно отключить его:

bool oldValidateOnSaveEnabled = localDb.Configuration.ValidateOnSaveEnabled;

try
{
  localDb.Configuration.ValidateOnSaveEnabled = false;

  var customer = new Customer { CustomerId = id };

  localDb.Customers.Attach(customer);
  localDb.Entry(customer).State = EntityState.Deleted;
  localDb.SaveChanges();
}
finally
{
  localDb.Configuration.ValidateOnSaveEnabled = oldValidateOnSaveEnabled;
}

Ответ 2

Если вы извлекли объект из базы данных, то он уже привязан к контексту, чтобы вы могли удалить его:

db.myTable.Remove(model);

но
если вы только что получили модель от редактирования или удаления представления по почте или сгенерировали ее самостоятельно, чтобы избежать 2 поездок в базу данных, тогда EF не знает об этом, и вы получите ошибку с указанной выше строкой (... не найденной в ObjectStateManager..), поэтому вы установите для своего состояния значение "Удалено", чтобы сообщить EF:

//generate it yourself if not posted from edit/delete view
//var model = new Model { Id = 123 };

//set to delete
db.Entry(model).State = EntityState.Deleted;
db.SaveChanges();

Ответ 3

Можете ли вы просто сделать это?

var customer = localDb.Customers.Single(o => o.CustomerId == id);
localDb.Customers.Remove(customer);
localDb.SaveChanges();

Ответ 4

public T Delete<T>(T obj) where T : class
        {
            T existing = context.Set<T>().Find(GetKeys(obj, context));

            if (existing != null)
            {
                context.Set<T>().Remove(existing);
                context.SaveChanges();
                return existing;
            }
            return null;
        }

private object[] GetKeys<T>(T entity, DbContext context) where T : class
        {
            ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext;
            ObjectSet<T> set = objectContext.CreateObjectSet<T>();
            var keyNames = set.EntitySet.ElementType
                                                        .KeyMembers
                                                        .Select(k => k.Name).ToArray();
            Type type = typeof(T);

            object[] keys = new object[keyNames.Length];
            for (int i = 0; i < keyNames.Length; i++)
            {
                keys[i] = type.GetProperty(keyNames[i]).GetValue(entity, null);
            }
            return keys;
        }

Ответ 5

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

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

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

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