简体   繁体   中英

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

public ActionResult Index(FormModel form)
{
    using (DBModels db = new DBModels())

    {
        var clients = from c in db.Clients
                      select c;

        if (!String.IsNullOrEmpty(form.SearchString))
        {
            clients = clients.Where(s => s.Full_Name.Contains(form.SearchString) || s.Class.Contains(form.SearchString)
            || s.Membership_Type.Contains(form.SearchString) || s.Membership_Type.Contains(form.SearchString) ||
            s.Notes.Contains(form.SearchString) || s.ClientID.Equals(form.SearchString));
        }
             if (form.IsChecked != null)
              {
                  clients = clients.Where(t => t.Paid == form.IsChecked);
              }
        return View(clients);

    }
}  

Don't understand why this error is happening. I added a search box to search through the database. I also added a tick box to show the unpaid clients. When I change

return View(clients); 

back to

return View(db.Client.ToList()); 

it works but is what i am trying to avoid as it shows all the list not the "clients" variable which shows the ones from the SearchString.

clients is an IQueryable. IQueryable doesn't enumerate it's values until the first iteration is requested. By that time, your DbContext has already been disposed, so the enumeration throws an exception.

To fix that, use something like

using (DBModels db = new DBModels())
{
    var clients = Enumerable.Empty<Client>();

    if (!String.IsNullOrEmpty(form.SearchString))
    {
        clients = db.Clients.Where(s => s.Full_Name.Contains(form.SearchString) || s.Class.Contains(form.SearchString)
        || s.Membership_Type.Contains(form.SearchString) || s.Membership_Type.Contains(form.SearchString) ||
        s.Notes.Contains(form.SearchString) || s.ClientID.Equals(form.SearchString));
    }

    if (form.IsChecked != null)
    {
        clients = clients.Where(t => t.Paid == form.IsChecked);
    }

    return View(clients.ToList());
}

In theory, you should avoid the database call until the ToList() is called, but it's been awhile since I went that route. Instead, I'd recommend using PredicateBuilder , from LinqKit, to build a query that will be completely run against the database, like so:

using (DBModels db = new DBModels())
{
    var predicate = PredicateBuilder.New<Client>(true);

    if (!String.IsNullOrEmpty(form.SearchString))
    {
        predicate.And(s => s.Full_Name.Contains(form.SearchString) || s.Class.Contains(form.SearchString)
        || s.Membership_Type.Contains(form.SearchString) || s.Membership_Type.Contains(form.SearchString) ||
        s.Notes.Contains(form.SearchString) || s.ClientID.Equals(form.SearchString));
    }

    if (form.IsChecked != null)
    {
        predicate.And(t => t.Paid == form.IsChecked);
    }

    return View(db.Clients.Where(predicate).ToList());
}

IQueryable type of data structures are for iteration purpose mainly, these won't don't yield value until ToList is used. That's why your object is not evaluated after the dbcontext is disposed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM