2014-01-13 1 views
1

하나의보기에서이를 수행하려고합니다. 아마도 이것이 최선의 방법이 아닐까요?다른 ViewModel에서 값을 반환하는 방법은 무엇입니까?

데이터 기반의 양식이 있습니다. 모든 질문은 질문 테이블에서 왔지만 응답은 응답 테이블을 채 웁니다. 다음은보기입니다.

@using Microsoft.AspNet.Identity 
    @model Template.Models.Question 

@{ 
    ViewBag.Title = "View question"; 
    var qtype = Model.QuestionTypeId; 
    ViewBag.Number = Model.Id - 7; 
    Html.BeginForm("ViewQuestion", "Question", FormMethod.Post, new { @class = "form-horizontal", role = "form" }); 
} 

<h4>Question #@ViewBag.Number</h4> 
<hr /> 
<h1> @Model.Question1</h1> 

@Html.AntiForgeryToken() 
<div> 

    @switch (qtype) 
    { 
     case 1: 
      // Textbox 
      @Html.TextArea("Answer", new { @class = "form-control", rows = "4", col = "5" });<br /><br /> 
      break; 
     case 2: 
      // Dropdown 
      <select class="form-control" id="Answer"> 
      @foreach (var item in Model.QuestionOptions.OrderBy(o => o.QuestionOptionRanking)) 
      { 
       <option value="@item.QuestionOption1">@item.QuestionOption1</option> 

      } 
      </select><br /><br /> 
      break; 
     case 3: 
      // Checkbox 
       <div class="checkbox"> 
       @foreach (var item in Model.QuestionOptions.OrderBy(o => o.QuestionOptionRanking)) 
        { 
        <input type="checkbox" name="Answer" value="@item.QuestionOption1" /> @item.QuestionOption1 <br /> 
        } 
       </div><br /><br /> 
       break; 
     case 4: 
      //  Radio buttons 
      foreach (var item in Model.QuestionOptions.OrderBy(o => o.QuestionOptionRanking)) 
      { 
       <div class="radio"> 
       <label> 
       <input type="radio" name="Answer" value="@item.QuestionOption1" /> 
       @item.QuestionOption1 
       </label> 
       </div> 
      }<br /><br /> 
      break; 
    } 

</div> 
<input type="hidden" name="QuestionId" value="@Model.Id" /> 
<input type="hidden" name="UserId" value="@User.Identity.GetUserId()" /> 
<div class="form-group"> 
    <div class="col-md-offset-2 col-md-10"> 
     <input type="submit" class="btn btn-default" value="Answer" /> 
    </div> 
</div> 

그리고 여기 내 ViewModel입니다.

using System; 
using System.Collections.Generic; 
using System.ComponentModel.DataAnnotations; 

namespace Template.Models 
{ 
public class GetQuestionViewModel 
{ 

    public int Id { get; set; } 

    public int PageNumber { get; set; } 

    public string Question1 { get; set; } 

    public int QuestionTypeId { get; set; } 

    public Nullable<int> LinkedTo { get; set; } 

    public Nullable<int> Options { get; set; } 

    public Nullable<int> QuestionRanking { get; set; } 

    public virtual ICollection<QuestionOption> QuestionOptions { get; set; } 

    public virtual QuestionType QuestionType { get; set; } 

    public virtual ICollection<Response> Responses { get; set; } 

    public virtual ICollection<AspNetUser> AspNetUsers { get; set; } 
} 

public class ResponseViewModel 
{ 
    [Required] 
    public string UserId { get; set; } 

    [Required] 
    public int QuestionId { get; set; } 

    [Required(ErrorMessage = "Please answer the question before submitting")] 
    public string Answer { get; set; } 

    [Required] 
    public string Source { get; set; } 

    [Required] 
    public string Status { get; set; } 

    [Required] 
    public System.DateTime DateStamp { get; set; } 

    public Nullable<int> Duplicate { get; set; } 

    public virtual Question Questions { get; set; } 

    public object SelectedValue { get; set; } 

    public virtual ICollection<QuestionOption> QuestionOptions { get; set; } 
} 
} 

나는 GetQuestionViewModel 전혀 일을하고 페이지를 채울 질문 모델의 .emdx 버전에 의존 한 얻을 수없는,하지만 내 작업이) 페이지에서 각 사용자의 응답을 표시하고, B) 임의의 수의 질문을 한 화면에 표시 할 수 있으므로 PageNumber 필드에 질문을 표시하십시오.

여기 내 컨트롤러입니다.하지만 더 많은 것을 볼 수 있듯이 작업보다 주석 처리되어 있습니다!

using System.Web.Mvc; 
using Template.Models; 

namespace Template.Controllers 
{ 
public class QuestionController : Controller 
{ 
    private WebTemplateEntities db = new WebTemplateEntities(); 

    // GET: /Questions/ViewQuestion/5 
    public ActionResult ViewQuestion(int? id) 
    { 
     if (id == null || id == 0 || id > 12) 
     { 
      id = 8; 
     } 
     var question = db.Questions.Find(id); 
     if (question == null) 
     { 
      return HttpNotFound(); 
     } 

     return View(question); 
    } 

    //  [Route("Questions/{page?}")] 
    //public ActionResult ViewQuestion(GetQuestionViewModel model, int? id) 
    //{ 
    // if (id == null || id == 0 || id > 12) 
    // { 
    //  //return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 
    //  id = 8; 
    //  //return RedirectToAction("/ViewQuestion/" + id); 
    // } 

    // var q = db.Questions.Find(id); 
    // var pageId = q.PageNumber; 

    // var questions = from q in db.Questions 
    //     where q.PageNumber == pageId 
    //     orderby q.QuestionRanking 
    //     select q; 
    // return View(questions); 
    // } 

    // POST: /Questions/ViewQuestion/5 
    [HttpPost] 
    public ActionResult ViewQuestion([Bind(Include = "QuestionId, Answer, UserId")] ResponseViewModel responseViewModel) 
    { 
     Response re = new Models.Response(); 
     re.Answer = responseViewModel.Answer; 
     if (re.Answer == null) 
     { 
      re.Answer = "Work in progress!"; 
      // re.Answer = responseViewModel.SelectedValue(); 
      // re.Answer = int.Parse(SelectList["Question.QuestionOption1"]); 
     } 
     re.UserId = responseViewModel.UserId; 
     re.QuestionId = responseViewModel.QuestionId; 
     var id = responseViewModel.QuestionId; 
     re.Source = "Web"; 
     re.Status = "New"; 
     re.DateStamp = System.DateTime.Now; 
     db.Responses.Add(re); 
     db.SaveChanges(); 

     return RedirectToAction("ViewQuestion/" + (id + 1)); 
    } 

    protected override void Dispose(bool disposing) 
    { 
     if (disposing) 
     { 
      db.Dispose(); 
     } 
     base.Dispose(disposing); 
    } 
    } 
} 

저는이 문제에 대해 글자 그대로 며칠 동안 노력해 왔으며 지금은 서클을 돌아 다니고 있습니다. 도움이나 조언을 주시면 감사하겠습니다.

+0

제쳐두고보기에 표시되는 질문 번호를 ID를 기반으로하는 것은 바람직하지 않습니다.Id는 당신의 구현을 완전히 불가 지 (agnostic)해야합니다. 실제 질문 번호를 저장하는 데 사용되는 별도의 필드가 있어야합니다. –

+0

동의. 내가 제대로 작동 할 수있을 때이를 페이지 번호로 바꿀 계획입니다. 그러나 나는 그 순간에 사용자의 답변을 표시하는데 집착하고있다. 둘 다 나를 괴롭 히고 있습니다! – Alex

+0

[경로 ...]가 작동합니까? 해당 URL로 이동하면 컨트롤러 메서드가 실행됩니까? –

답변

0

당신이 Entity 모델과 ViewModels를 혼동하는 것처럼 보입니다. 보기에서 Template.Models.Question을 참조하며 이는 ViewModel이 아닌 Entity 인 것으로 나타납니다.

뷰는 엔터티가 아닌 ViewModel 만 참조해야합니다. 또한 엔티티와 ViewModel간에 매핑 메커니즘이 설정되어 있어야합니다. 또 다른 사실은 Entity와 ViewModel이 애플리케이션의 동일한 네임 스페이스에있는 것처럼 보인 점입니다. 이것은 반드시 문제는 아니지만 ViewModel이보기에만 관련되고 Entities가 지속성 계층과 관련되기 때문에 혼란 스러울 수 있습니다.

현재 귀하의 코드는 다음을 통해 질문 객체를 얻습니다 : from q in db.Questions 그러면 View (질문)로 전달됩니다. 따라서 뷰에서 실제로 ViewModel을 사용할 수는 없으며 엔티티 모델이됩니다.

은 당신의보기를 변경

:

@model Template.Models.GetQuestionViewModel 

그리고 이런 식으로 컨트롤러를 변경합니다

var questions = (from q in db.Questions 
       where q.PageNumber == pageId 
       orderby q.QuestionRanking 
       select q.ToViewModelExtensionMethod()).ToList(); 

return View(questions); 

당신은 Template.Model에서 매핑을 수행하는 확장 메서드를 작성해야합니다. 질문. Template.Model.GetQuestionViewModel.

희망이 도움이됩니다.

업데이트

는 확장 방법에 대한 정보를 들어, 다음은 MSDN article입니다.

나는 구문의 흐름이 마음에 들기 때문에 확장 메서드 만 사용합니다. 다음은 간단한 예입니다.

namespace Template.Models.Extensions 
{ 
    public static class QuestionExtensions 
    { 
     public static GetQuestionViewModel ToViewModelExtensionMethod(this Question question) 
     { 
      var result = new GetQuestionViewModel(); 
      result.field1 = question.field1; 
      // ... etc 
      return result; 
     } 
    } 
} 

위의 변경 사항에 유의하십시오. 여기서 항목을 쿼리 할 때 매핑 할 곳을 기록하십시오.

+0

올바른 Aaron, 엔터티 및 viewmodels 혼동입니다. "매핑을 수행하는 확장 메서드"가 의미하는 것의 세부 정보 나 샘플을 나에게 줄 수 있습니까? 실제로 이것이 나를 혼란스럽게하는 부분입니까? – Alex

관련 문제