2013-03-22 3 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에서 인스턴스를 다시로드하기 위해 특별히이 줄에 추가했습니다. 지연로드 목록 클래스를 다시 채울 것으로 가정하고 이름 요청과 마찬가지로 가져온 요청과 동일한 인스턴스 데이터를 갖게됩니다. 변경됨 :

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

게시판에 하위 클래스가로드되지 않는 이유는 무엇입니까?

일단이 문제가 해결되면 데이터베이스에 레코드가없는 클라이언트를 탐색 할 경우를 대비하여 Client 클래스에서 List 클래스를 인스턴스화하는 생성자를 추가하는 것이 좋습니다.

+0

곳'초기화 db'입니까? – qujck

+0

@qujck - ClientController에서 – Sean

+1

수정 내용이 DB에 저장되어 있습니까? 액션의 클라이언트 인수는 액션 서명에 따라 모델 바인더에 의해 생성 된 "모델 클래스"(엔터티 프록시 클래스 imho가 아님)이기 때문입니다. 클라이언트 클래스에는 Projects를 초기화하는 생성자가 없으므로 프로젝트는 기본값 인 null을 얻습니다. – tschmit007

답변

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

프로젝트가 재 뷰에 다시 전달되기 전에 유효성 검사가 실패하면 연결됩니다. 이론 상으로는 액션 리디렉션 대신 작동해야합니다. 나는 그것을 밖으로 시도 할 것이다.

+0

또 다른 옵션은 부분 뷰를 사용하여 데이터베이스에서 직접 프로젝트의 모델을 전달하므로 업데이트 된 모델 인스턴스에서 가져 오지 않습니다. – Sean

0

컨텍스트에 이미 클라이언트의 로컬 복사본이 있으므로 클라이언트를 다시로드하기 위해 추가 한 줄은 아무 것도 수행하지 않습니다. 업데이트를하기 전에 클라이언트/프로젝트를 열심히로드함으로써이를 증명할 수 있습니다. (이 같은)

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

감사하지만 작동하지 않았습니다. 디버깅 할 경우 : 저장하기 전에 프로젝트가 없습니다. 저장 후에도 프로젝트가 없습니다. 내 강제로드 후 (찾기) - 여전히 프로젝트가 없습니다. – Sean

+0

List는 ICollection을 구현합니다 ... – Sean

+1

ICollection을 사용하면 EF가 원하는 클래스를 제공 할 수 있음을 의미합니다. List는 List 여야 함을 의미합니다. – qujck

3

게시 MVC에서 실제 POCO 인스턴스 인 가 아닌이 POCO에서 파생 된 프록시 클래스의 인스턴스를 구성하기 때문입니다. 따라서 지연로드를 수행하기 위해 재정의 된 가상 속성이 없습니다.

이 솔루션은 명시 적으로 항목을 통해 컬렉션을로드하는 것입니다 (당신의 Clients.Find (ID) 호출을 대체 할) :

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