C# 操作无法完成,因为 DbContext 已被处理错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13617698/
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 09:12:05  来源:igfitidea点击:

The operation cannot be completed because the DbContext has been disposed error

c#entity-frameworkextension-methods

提问by Colin

I'm new to EF and I'm trying to use an extension method which converts from my Database type Userto my info class UserInfo.
I'm using database first if that makes a difference?

我是 EF 的新手,我正在尝试使用一种扩展方法,该方法将我的 Database 类型转换User为我的 info 类UserInfo
如果这有区别,我首先使用数据库?

My code below gives the error

我下面的代码给出了错误

The operation cannot be completed because the DbContext has been disposed.

操作无法完成,因为 DbContext 已被释放。

try
{
    IQueryable<User> users;
    using (var dataContext = new dataContext())
    {
        users = dataContext.Users
                  .Where(x => x.AccountID == accountId && x.IsAdmin == false);
        if(users.Any() == false)
        {
            return null;
        }
    }
    return users.Select(x => x.ToInfo()).ToList(); // this line is the problem
}
catch (Exception ex)
{
    //...
}

I can see why it would do it, but I also don't understand why the result of the where statement isn't being saved into the usersobject?

我可以理解它为什么会这样做,但我也不明白为什么 where 语句的结果没有保存到users对象中?

So I guess my main question is why doesn't it work and secondly what's the right way of using extension methods and EF?

所以我想我的主要问题是为什么它不起作用,其次使用扩展方法和 EF 的正确方法是什么?

采纳答案by JofryHS

This question & answerlead me to believe that IQueryable require an active context for its operation. That means you should try this instead:

这个问题和答案让我相信 IQueryable 需要一个活动上下文来进行操作。这意味着你应该试试这个:

try
{
    IQueryable<User> users;

    using (var dataContext = new dataContext())
    {
        users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false);

        if(users.Any() == false)
        {
            return null;
        }
        else
        {
            return users.Select(x => x.ToInfo()).ToList(); // this line is the problem
        }
    }


}
catch (Exception ex)
{
    ...
}

回答by JBrooks

The reason why it is throwing the error is the object is disposed and after that we are trying to access the table values through the object, but object is disposed.Better to convert that into ToList() so that we can have values

抛出错误的原因是对象被释放,之后我们试图通过对象访问表值,但对象被释放。最好将其转换为 ToList() 以便我们可以拥有值

Maybe it isn't actually getting the data until you use it (it is lazy loading), so dataContext doesn't exist when you are trying to do the work. I bet if you did the ToList() in scope it would be ok.

也许在您使用它之前它实际上并没有获取数据(它是延迟加载),因此当您尝试完成工作时 dataContext 不存在。我敢打赌,如果您在范围内执行 ToList() 就可以了。

try
{
    IQueryable<User> users;
    var ret = null;

    using (var dataContext = new dataContext())
    {
        users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false);

        if(users.Any())
        {
            ret = users.Select(x => x.ToInfo()).ToList(); 
        }

     }

   Return ret;
}
catch (Exception ex)
{
    ...
}

回答by Steve Py

Objects exposed as IQueryable<T>and IEnumerable<T>don't actually "execute" until they are iterated over or otherwise accessed, such as being composed into a List<T>. When EF returns an IQueryable<T>it is essentially just composing something capable of retrieving data, it isn't actually performing the retrieve until you consume it.

暴露为IQueryable<T>和 的对象在IEnumerable<T>被迭代或以其他方式访问之前实际上不会“执行”,例如组合成List<T>. 当 EF 返回 an 时,IQueryable<T>它本质上只是组成了一些能够检索数据的东西,它实际上并没有执行检索,直到您使用它为止。

You can get a feel for this by putting a breakpoint where the IQueryableis defined, vs. when the .ToList()is called. (From inside the scope of the data context as Jofry has correctly pointed out.) The work to pull the data is done during the ToList()call.

您可以通过在IQueryable定义的位置放置断点来感受这一点,而不是在.ToList()调用时。(从 Jofry 正确指出的数据上下文范围内。)提取数据的工作是在ToList()调用期间完成的。

Because of that, you need to keep the IQueryable<T>within the scope of the data context.

因此,您需要将 保持IQueryable<T>在数据上下文的范围内。

回答by Joe Enzminger

You need to remember that IQueryable queries are not actually executed against the data store until you enumerate them.

您需要记住,在您枚举它们之前,IQueryable 查询实际上不会针对数据存储执行。

using (var dataContext = new dataContext())
{

This line of code doesn't actually do anything other than build the SQL statement

这行代码除了构建 SQL 语句之外实际上并没有做任何事情

    users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false);

.Any() is an operation that enumerates the IQueryable, so the SQL is sent to the data source (through dataContext), and then the .Any() operations is executed against it

.Any() 是枚举IQueryable 的操作,因此将SQL 发送到数据源(通过dataContext),然后对其执行.Any() 操作

    if(users.Any() == false)
    {
        return null;
    }
}

Your "problem" line is reusing the sql built above, and then doing an additional operation (.Select()), which just adds to the query. If you left it here, no exception, except your problem line

您的“问题”行正在重用上面构建的 sql,然后执行附加操作 (.Select()),它只是添加到查询中。如果你把它留在这里,也不例外,除了你的问题行

return users.Select(x => x.ToInfo()).ToList(); // this line is the problem

calls .ToList(), which enumerates the IQueryable, which causes the SQL to be sent to the datasource through the dataContext that was used in the original LINQ query. Since this dataContext has been disposed, it is no longer valid, and .ToList() throws an exception.

调用 .ToList(),它枚举 IQueryable,这会导致 SQL 通过原始 LINQ 查询中使用的 dataContext 发送到数据源。由于此 dataContext 已被处理,它不再有效,并且 .ToList() 抛出异常。

That is the "why it doesn't work". The fix is to move this line of code inside the scope of your dataContext.

这就是“为什么它不起作用”。解决方法是将这行代码移到 dataContext 的范围内。

How to use it properly is another question with a few arguably correct answers that depend on your application (Forms vs. ASP.net vs. MVC, etc.). The pattern that this implements is the Unit of Work pattern. There is almost no cost to creating a new context object, so the general rule is to create one, do your work, and then dispose of it. In web apps, some people will create a Context per request.

如何正确使用它是另一个问题,其中有一些可以说是正确的答案,这取决于您的应用程序(Forms 与 ASP.net 与 MVC 等)。这实现的模式是工作单元模式。创建一个新的上下文对象几乎没有成本,所以一般规则是创建一个,完成你的工作,然后处理它。在 Web 应用程序中,有些人会为每个请求创建一个上下文。

回答by Grant Cermak

This can be as simple as adding ToList() in your repository. For example:

这可以像在您的存储库中添加 ToList() 一样简单。例如:

public IEnumerable<MyObject> GetMyObjectsForId(string id)
{
    using (var ctxt = new RcContext())
    {
        // causes an error
        return ctxt.MyObjects.Where(x => x.MyObjects.Id == id);
    }
}

Will yield the Db Context disposed error in the calling class but this can be resolved by explicitly exercising the enumeration by adding ToList() on the LINQ operation:

将在调用类中产生 Db Context 处理错误,但这可以通过在 LINQ 操作上添加 ToList() 显式执行枚举来解决:

public IEnumerable<MyObject> GetMyObjectsForId(string id)
{
    using (var ctxt = new RcContext())
    {
        return ctxt.MyObjects.Where(x => x.MyObjects.Id == id).ToList();
    }
}

回答by ComeIn

Change this:

改变这个:

using (var dataContext = new dataContext())
{
    users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false);

    if(users.Any())
    {
        ret = users.Select(x => x.ToInfo()).ToList(); 
    }

 }

to this:

对此:

using (var dataContext = new dataContext())
{
    return = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false).Select(x => x.ToInfo()).ToList();
} 

The gist is that you only want to force the enumeration of the context dataset once. Let the caller deal with empty set scenario, as they should.

要点是您只想强制枚举上下文数据集一次。让调用者处理空集场景,因为他们应该这样做。

回答by Niraj Trivedi

Here you are trying to execute IQueryable object on inactive DBContext. your DBcontext is already disposed of. you can only execute IQueryable object before DBContext is disposed of. Means you need to write users.Select(x => x.ToInfo()).ToList()statement inside using scope

在这里,您尝试在非活动 DBContext 上执行 IQueryable 对象。你的 DBcontext 已经被处理掉了。您只能在处理 DBContext 之前执行 IQueryable 对象。意味着您需要users.Select(x => x.ToInfo()).ToList()在使用范围内编写语句

回答by Rajesh Kamble

using(var database=new DatabaseEntities()){}

Don't use using statement. Just write like that

不要使用 using 语句。就这样写

DatabaseEntities database=new DatabaseEntities ();{}

It will work.

它会起作用。

For documentation on the usingstatement see here.

有关该using声明的文档,请参见此处