C# 无法删除对象,因为在实体框架 5 的 ObjectStateManager 中找不到

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15637965/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 17:26:33  来源:igfitidea点击:

The object cannot be deleted because it was not found in the ObjectStateManager in entity framework 5

c#entity-framework-5

提问by Rameez Ahmed Sayad

I'm trying to delete an object using EntityFramework 5 but i get this error. The object cannot be deleted because it was not found in the ObjectStateManager
I am using the Remove()method as DeleteObject()is not present in EF5. Can anyone help what am I missing?

我正在尝试使用 EntityFramework 5 删除一个对象,但出现此错误。 无法删除该对象,因为它在 ObjectStateManager 中找不到
我正在使用EF5 中不存在的Remove()方法DeleteObject()。任何人都可以帮助我错过什么吗?

This does not work for Remove

这不适用于删除

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

Another thing I tried from msdn to change the state to Deleted. But here it gives an error saying all the fields should be present. Is it necessary to get the complete record then delete?

我尝试从 msdn 将状态更改为已删除的另一件事。但在这里它给出了一个错误,说所有的字段都应该存在。是否有必要获取完整记录然后删除?

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

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

Any inputs?

任何输入?

采纳答案by Nicholas Butler

You can fetch the row from the database and then delete it, but this causes 2 round trips to the database.

您可以从数据库中获取该行然后将其删除,但这会导致到数据库的 2 次往返。

If you want to do it in one hit, your second version with Attachwill work - as long as the entity is not already loaded into the context.

如果您想一次性完成,您的第二个版本Attach就可以使用 - 只要实体尚未加载到上下文中。

The error you are getting is caused by EF validation which runs before any database write.

您得到的错误是由在任何数据库写入之前运行的 EF 验证引起的。

You can turn it off temporarily like this:

您可以像这样暂时关闭它:

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

回答by Mike C.

Can you just do this?

你能做到这一点吗?

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

回答by Moji

if you retrieved object from database then it's already attached to the context so you can delete by:

如果您从数据库中检索对象,那么它已经附加到上下文,因此您可以通过以下方式删除:

db.myTable.Remove(model);

but
if you just received model from edit or delete view by post or generated it yourself to avoid 2 trips to database then EF doesn't know about it and you get error with above line (..not found in the ObjectStateManager..) so you set its state to "Deleted" to inform EFby:

但是,
如果您刚刚通过帖子从编辑或删除视图中收到模型,或者自己生成模型以避免 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();

回答by GLeBaTi

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

回答by Terkhos

I know this question is quite old but none of the above worked for me since i was deleting registers from more than one class/service at once and each one of them was instantiating it's own database connection context.

我知道这个问题已经很老了,但以上都不适合我,因为我一次从多个类/服务中删除寄存器,并且每个类/服务都在实例化它自己的数据库连接上下文。

What i did to solve it was to send the first created context to the rest of the classes/services that where going to access the database.

我为解决它所做的是将第一个创建的上下文发送到将要访问数据库的其余类/服务。

For example, my serviceAwas going to delete some of it's registers and call serviceBand serviceCto do the same with their registers.

例如,我serviceA打算删除它的一些寄存器并调用serviceB并对serviceC它们的寄存器执行相同的操作。

I would then delete my registers on serviceAand pass as a parameter the context created on the serviceAto serviceBand serviceC.

然后我会删除我的寄存器serviceA并将在serviceAtoserviceB和上创建的上下文作为参数传递serviceC