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

后端 未结 8 1887
情歌与酒
情歌与酒 2020-11-29 09:22

I\'m new to EF and I\'m trying to use an extension method which converts from my Database type User to my info class UserInfo.
I\'m using data

相关标签:
8条回答
  • 2020-11-29 09:37

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

    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)
    {
        ...
    }
    
    0 讨论(0)
  • 2020-11-29 09:37

    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.

    You can get a feel for this by putting a breakpoint where the IQueryable is 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.

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

    0 讨论(0)
  • 2020-11-29 09:37

    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

    0 讨论(0)
  • 2020-11-29 09:37
    using(var database=new DatabaseEntities()){}
    

    Don't use using statement. Just write like that

    DatabaseEntities database=new DatabaseEntities ();{}
    

    It will work.

    For documentation on the using statement see here.

    0 讨论(0)
  • 2020-11-29 09:39

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

    using (var dataContext = new dataContext())
    {
    

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

        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

        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

    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.

    That is the "why it doesn't work". The fix is to move this line of code inside the scope of your 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.

    0 讨论(0)
  • 2020-11-29 09:42

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

    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:

    public IEnumerable<MyObject> GetMyObjectsForId(string id)
    {
        using (var ctxt = new RcContext())
        {
            return ctxt.MyObjects.Where(x => x.MyObjects.Id == id).ToList();
        }
    }
    
    0 讨论(0)
提交回复
热议问题