The ObjectContext instance has been disposed and c

2019-01-11 22:00发布

问题:

This question already has an answer here:

  • Solving “The ObjectContext instance has been disposed and can no longer be used for operations that require a connection” InvalidOperationException 7 answers

I have this view:

@model MatchGaming.Models.ProfileQuery
@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>    
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@using (Html.BeginForm("Results", "Profiles")) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>ProfileQuery</legend>
        @Html.EditorFor(model=>model.SearchString)
        <p>
            <input type="submit" value="Create" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

I have this controller for the HttpPost:

[HttpPost]
public ActionResult Results(ProfileQuery profileQuery)
{
    Debug.Write(profileQuery.SearchString);
    using(var db = new MatchGamingEntities())
    {
        var SearchUserName = db.Users.SingleOrDefault(a=> a.UserName.Contains(profileQuery.SearchString));
        var Users = from m in db.Users
                    join m2 in db.MyProfiles on m.UserId equals m2.UserId
                    where m.UserName == SearchUserName.UserName
                    select new UserViewModel
                    {
                        UserName = m.UserName,
                        LastActivityDate = m.LastActivityDate,
                        Address = m2.Address,
                        City = m2.City,
                        State = m2.State,
                        Zip = m2.Zip
                    };

        return View(Users.AsEnumerable());
    }
}

Here is the View for Results:

@model IEnumerable<MatchGaming.Models.UserViewModel>    
@{
    ViewBag.Title = "Results";
}

<h2>Results</h2>

<fieldset>
    <legend>UserViewModel</legend>
    @foreach (var item in Model){
    <div class="display-label">UserName</div>
    <div class="display-field">@item.UserName</div>

    <div class="display-label">LastActivityDate</div>
    <div class="display-field">@String.Format("{0:g}", item.LastActivityDate)</div>

    <div class="display-label">Address</div>
    <div class="display-field">@item.Address</div>

    <div class="display-label">City</div>
    <div class="display-field">@item.City</div>

    <div class="display-label">State</div>
    <div class="display-field">@item.State</div>

    <div class="display-label">Zip</div>
    <div class="display-field">@item.Zip</div>
    }
</fieldset>

I keep getting this error:

The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.

I can't figure out why.

回答1:

I am guessing that the problem is that the execution of your LINQ query has been deferred until starting to access them on your view. At this point db has already been disposed.

Try this:

return View(Users.ToList());

Added ToList()

That will force the fetch from the DB before disposing db.



回答2:

Your using clause is disposing of (read: destroying) the MatchGamingEntities db context before the View has a chance to use it. So while you can just enumerate the items before (or as) you pass the Users to the View, a better approach is to drop your use of the using clause and let natural garbage collection do its work after you truly done with it--which won't be until after the View is done.

For more information, see this question on the Entity Framework and Connection Pooling.



回答3:

The problem is this line:

return View(Users.AsEnumerable());

The enumeration is lazily evaluated, and since your MatchGamingEntities is disposed of before your view can cycle through the enumeration, the code dies when it tries to do just that.

You will either have to find a way to manage the lifetime of your db object in such a way that it lives beyond the controller method, or bring all your data into in-memory Model objects before passing them to the view.

see here for a similar explanation.



回答4:

A bad practice, but you can set

this.ContextOptions.LazyLoadingEnabled = false;

in the constructor of the Context



回答5:

The problem is that you are issuing a Shallow Copy when you do:

 var Users = from m in db.Users
                join m2 in db.MyProfiles on m.UserId equals m2.UserId
                where m.UserName == SearchUserName.UserName
                select new UserViewModel
                {
                    UserName = m.UserName,
                    LastActivityDate = m.LastActivityDate,
                    Address = m2.Address,
                    City = m2.City,
                    State = m2.State,
                    Zip = m2.Zip
                };

What you need to do is make a UsersCopy and then iterate through Users copying the values to the UsersCopy and then return UsersCopy in order to do a Deep Copy

Something like

List<User> UsersCopy = new List<User>();
foreach(user in Users){
  User u = new User();
  u.UserName = user.UserName;
  u.Address = user.Address;
  //...
  UsersCopy.Add(u);
}
return View(UsersCopy);


回答6:

In case you are having problem displaying child property i.e Line items. Here is the dirty fix that worked for me. Fixed my problem of not retrieving the child items of an object:

header.MachineDataLines = header.MachineDataLines;