Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lazy loading class not loading - MVC

I have clients:

public class Client
{
    public int ClientID { get; set; }
    public string ClientName { get; set; }
    public virtual List<Project> Projects { get; set; }
}

And projects:

public class Project
{
    public int ProjectID { get; set; }
    public string ProjectName { get; set; }
}

The client controller has a details get action:

public ActionResult Details(int id)
{
    Client client = db.Clients.Find(id);
    return View(client);
}

And a details post action:

[HttpPost]
public ActionResult Details(Client client)
{
    if (ModelState.IsValid)
    {
        db.Entry(client).State = EntityState.Modified;
        db.SaveChanges();
                    // reload object from db to populate projects property
        client = db.Clients.Find(client.ClientID);
    }
    return View(client);
}

My client details view:

@model Client
<h1>@Html.DisplayFor(model => model.ClientName)</h1>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Client</legend>

        @Html.HiddenFor(model => model.ClientID)

        <div class="editor-label">
            @Html.LabelFor(model => model.ClientName)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ClientName)
            @Html.ValidationMessageFor(model => model.ClientName)
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

<h2>Projects</h2>

<ul>
@foreach (Project project in Model.Projects)
{
    <li>@Html.ActionLink(project.ProjectName, "Details", "Project", new { id = project.ProjectID }, null)</li>
}
</ul>

Now if I go to a client which has projects, it works fine, I see the client name in the textbox, and a list of projects. I edit the name and click Save. But then the view errors on the subclass list iteration, "Object reference not set to an instance of an object."

I added in this line specifically to reload the instance from the db, assuming it would then repopulate the lazy-loading list class, and I would have the same instance data as I had in the get request, just with the name changed:

client = db.Clients.Find(client.ClientID);

Why is it not loading the subclass on the postback?

Once I have this fixed, would it be a good idea in the Client class, to add a constructor that instantiates the List class, in case I navigate to a Client that doesn't have any records in the database?

like image 245
Sean Avatar asked May 08 '26 15:05

Sean


1 Answers

The reason is that on post MVC is constructing an instance of the actual POCO, NOT an instance of the proxy class that derives from the POCO. Therefore, there is no overridden virtual property to perform the lazy loading.

The solution is to explicitly load the collection via the entry (to replace your Clients.Find(id) call):

db.Entry(client).Collection( c => c.Projects ).Load();
like image 155
Moho Avatar answered May 11 '26 05:05

Moho



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!