2013-03-22 107 views
3

我有客戶:延遲加載類不加載 - MVC

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重新加載實例,假設它會重新填充lazy-loading list類,並且我將擁有與我在get請求中一樣的實例數據,只是名稱已更改:

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

爲什麼它不在回發中加載子類?

一旦我解決了這個問題,在Client類中添加一個實例化List類的構造函數,以防導航到在數據庫中沒有任何記錄的客戶端時,

+0

其中'db'初始化? – qujck 2013-03-22 09:25:28

+0

@qujck - 在ClientController中 – Sean 2013-03-22 09:28:16

+1

您確定您的修改已保存在數據庫中嗎?因爲您的動作的客戶端參數是根據您的動作簽名由模型聯編程序生成的「模型類」(而非實體代理類imho)。由於客戶端類沒有構造器初始化項目,因此項目會獲取默認值:null。 – tschmit007 2013-03-22 09:29:16

回答

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重定向。我也會試一試。

+0

這裏的另一個選擇是使用局部視圖,並將該數據庫中的項目直接傳遞給該視圖,因此它不是來自更新後的模型實例。 – Sean 2013-03-22 15:15:35

0

由於上下文已經擁有客戶端的本地副本,因此添加到重新加載客戶端的行不會執行任何操作。您可以通過在進行更新之前急切地加載客戶端/項目來證明這一點。 (像這樣)

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

謝謝,但它沒有奏效。如果我調試它:保存之前,它沒有項目。保存後,仍然沒有項目。在我的強制重裝(Find)之後 - 仍然沒有任何項目。 – Sean 2013-03-22 09:20:19

+0

列表無論如何實現ICollection ... – Sean 2013-03-22 09:21:18

+1

使用'ICollection'意味着EF可以提供任何它喜歡的類,'List'意味着它必須是一個'List' – qujck 2013-03-22 09:23:05

3

原因是在發佈MVC構造實際POCO的實例時,而不是從POCO派生的代理類的實例。因此,沒有重寫的虛擬屬性執行延遲加載。

的解決方案是通過進入顯式地加載集合(更換您的Clients.Find(ID)調用):

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