懒加载类没有加载 - MVC

时间:2013-03-22 09:06:04

标签: asp.net-mvc entity-framework lazy-loading

我有客户:

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

项目:

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

客户端控制器有一个详细信息获取操作:

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

详情发布后:

[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);
}

我的客户详情视图:

@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>

现在,如果我去一个有项目的客户端,它工作正常,我在文本框中看到了客户端名称,以及一个项目列表。我编辑名称并单击“保存”。但随后子类列表上的视图错误迭代,“对象引用未设置为对象的实例。”

我在这一行中特意添加了从db重新加载实例,假设它会重新填充延迟加载列表类,并且我将获得与get请求中相同的实例数据,只需更改名称:

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

为什么不在回发中加载子类?

一旦我修复了这个问题,在Client类中添加一个实例化List类的构造函数是不是一个好主意,以防我导航到数据库中没有任何记录的客户端?

3 个答案:

答案 0 :(得分:3)

原因是在MVC上构建了一个实际POCO的实例, NOT 是一个派生自POCO的代理类的实例。因此,没有重写的虚拟属性来执行延迟加载。

解决方案是通过条目显式加载集合(替换你的Clients.Find(id)调用):

db.Entry(client).Collection( c => c.Projects ).Load();

答案 1 :(得分:1)

我将不得不考虑ApplyCurrentValues,但目前,这就是我的工作方式:

    [HttpPost]
    public ActionResult Details(Client client)
    {
        if (ModelState.IsValid)
        {
            db.Entry(client).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Details", new { msg = "saved" });
        }
        client.Projects = db.Clients.Find(client.ClientID).Projects;
        return View(client);
    }

如果验证失败,则会在传回视图之前重新附加项目。理论上,这应该起作用而不是Action重定向。我也会尝试一下。

答案 2 :(得分:0)

您为重新加载客户端而添加的行将不会执行任何操作,因为上下文已具有客户端的本地副本。您可以通过在进行更新之前急切加载客户端/项目来证明这一点。 (像这样)

client = db.Clients.Find(client.ClientID);
client.Projects.ToList();
db.Entry(client).State = EntityState.Modified;
db.SaveChanges();