4

I am creating an C# Web application, where I would be able to add companies and the places the company has its branches. A company could have several location branches. And for one location there could be several companies. So the relationship between Companies and Territory is Many-Many.

This is my current model for Company,

public class CompanyModel
{

    [HiddenInput(DisplayValue = false)]
    public long CompanyId { get; set; }

    [Display(Name = "Company Name")]
    [Required(ErrorMessage = "* required")]
    public string CompanyName { get; set; }

    [Display(Name = "Phone Number")]
    [Required(ErrorMessage = "* required")]
    [RegularExpression(@"\d*", ErrorMessage = "Not a valid phone number")]
    public string PhoneNo { get; set; }


    [Display(Name = "Post Code List", Prompt = "eg. BA5, BS16")]
    public string PostCodeList { get; set; }
}

It has the text box which will take in a comma separated string. So I iterate it using foreach to add it to the table,

            foreach (var s in company.PostCodeList.Split(','))
            {
                AddPostCode(s, company.CompanyId);
            }

Where AddPostcode is,

    public void AddPostCode(string postCode, long companyId)
    {
        using (var db = new BoilerServicingDbContext())
        {
            //Does post code exist
            var p = db.Territories.FirstOrDefault(x => x.PostCodePrefix == postCode);

            //if not create
            if (p == null)
            {
                p = new Territory
                {
                    PostCodePrefix = postCode
                };
                db.Territories.Add(p);
            }
            //get the company
            var c = db.Companies.First(x => x.Id == companyId);

            //add post code
            c.Territories.Add(p);

            //save
            db.SaveChanges();
        }
    }

Now I get the following error,

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

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.InvalidOperationException: The operation cannot be completed because the DbContext has been disposed.

Exception Details: System.InvalidOperationException: Sequence contains no elements

Source Error:

Line 16:         </thead>
Line 17:         <tbody>
Line 18:         @foreach (var a in Model)
Line 19:             {
Line 20:                 <tr>

Source File: c:\Source\LSP.HEA.BoilerServicing\Main\LSP.HEA.BoilerServicing.Web\Views\Companies\Index.cshtml
Line: 18 
octavioccl
  • 35,665
  • 6
  • 76
  • 95
PaulFrancis
  • 5,560
  • 1
  • 16
  • 34
  • Post the rest of the loop from your view (where the exception is actually occuring) along with the controller action that renders the view. – Craig W. Feb 12 '15 at 18:01
  • possible duplicate of [The ObjectContext instance has been disposed and can no longer be used for operations that require a connection](http://stackoverflow.com/questions/5360372/the-objectcontext-instance-has-been-disposed-and-can-no-longer-be-used-for-opera) – James Sampica Feb 12 '15 at 22:56

1 Answers1

8

This happens because you're waiting until the view is rendered to iterate the collection generated by an EF query, and the context has already been disposed at this point.

EF doesn't actually run the SQL query until the collection is accessed, so you need to force it to pull the data and populate the collection while the DbContext is still alive.

A simple solution to this is to use ToList(), which causes EF to immediately retrieve the data.

For example, instead of:

return View(mycollection);

Try:

return View(mycollection.ToList());
Alan
  • 2,822
  • 2
  • 11
  • 16
  • It's also generally a bad idea to use `using` with your context anyways. Your context should be instantiated per request. Any more frequently than that and you're apt to run into issues like this one or being told that the object you're trying to save or some related object belongs to another context. – Chris Pratt Feb 12 '15 at 20:57
  • Also, @Alan, the OP would need to call `.ToList` within the `AddPostCode` method, not while returning the view. Otherwise, it's the same problem. The context has already been disposed. – Chris Pratt Feb 12 '15 at 20:59
  • @ChrisPratt I was assuming the OP's problem is actually elsewhere, as I read the `AddPostcode()` method as a self contained (void) function. Really need to see more code to give a proper answer. I totally agree with the first point - I generally use the OwinContext to hold the DbContext, but that's in MVC5 projects which bring OWIN in by default. – Alan Feb 12 '15 at 21:10
  • OwinContext works, and Microsoft actually uses it for dependency resolution in Identity, so it somewhat has the official seal of approval. It *feels* wrong to me, though. I prefer to use a true DI container for such purposes, which would work with or without OWIN support in the app. – Chris Pratt Feb 12 '15 at 21:20
  • Alan, thank you for your response. I will have to be honest, I did not understand most of what you said. I am really new to C# and MVC, this is my very first app, and I have no background of what Model, View and Controller are, let alone understand how they work. I used your advice to use ToList in the method that uses the Query. It work amazing. Thank you ! – PaulFrancis Feb 13 '15 at 10:44
  • @ChrisPratt, I am not sure how/why, but my understanding is that the `AddPostcode()`is called from the iteration, by passing a postcode and the ID of the company that has just been created. As the method has its own using statement, the context is created for ever loop run. Am I wrong? – PaulFrancis Feb 13 '15 at 10:49