2016-11-08 2 views
1

У меня есть приложение для создания и редактирования опросов. Каждое обследование содержит набор вопросов и ответы (ответы). Когда создается опрос, набор вопросов генерируется из отдельной таблицы Questions. Каждый год для каждого пользователя создается новый опрос с одним и тем же набором вопросов, с тем чтобы ответы могли сравниваться с течением времени.Создайте редактирующую модель на основе связанных данных

Когда создается опрос, ответы на каждый вопрос сохраняются, но пользователь может не дать ответа на каждый вопрос, и теперь мне нужно создать представление для редактирования существующих ответов.

Модели

public class Survey 
{ 
    public int ID { get; set; } 
    public int AreaID { get; set; } 
    public Status Status { get; set; } 
    public DateTime AssessmentDate { get; set; } 
    public virtual Area Area { get; set; } 
    public virtual ICollection<Answer> Answers { get; set; } 
} 
public class Question 
{ 
    public int ID { get; set; } 
    public string QuestionText { get; set; } 
    public virtual ICollection<Answer> Answers { get; set; } 
} 
public class Answer 
{ 
    public int ID { get; set; } 
    public int? Response { get; set; } 
    public int QuestionID { get; set; } 
    public int SurveyID { get; set; } 
    public virtual Question Question { get; set; } 
    public virtual Survey Survey{ get; set; } 
} 

Вот мой ViewModel, что я использую, чтобы создать свой взгляд на экран редактирования

public class SurveyResponseViewModel 
{ 
    public Assessment Assessment { get; set; } 
    public IEnumerable<Question> Questions { get; set; } 
} 

и кода в методе GET является

public ActionResult Edit(int? id) 
{ 
    if (id == null) 
    { 
     return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 
    } 
    Survey survey = db.Surveys.Find(id); 
    var viewModel = new SurveyResponseViewModel 
    { 
     Survey = survey, 
     Areas = new SelectList(db.Areas, "ID", "SubLevel").ToList(), 
     Questions = db.Questions.Where(q => q.isActive) 
    }; 
    if (survey == null) 
    { 
     return HttpNotFound(); 
    } 
    return View(viewModel); 
} 

Это заполняет мою модель представления всеми вопросами, но каждый вопрос содержит набор ответов. Как отображать и редактировать только ответ на каждый вопрос, связанный с этим опросом в представлении?

@foreach (var question in Model.Questions) 
{ 
    // Display the question 
    @Html.Raw(question.QuestionText) 
    // How to create an input for the associated response?? 
    <input type="text" name="????" placeholder="Enter a number..." value="????" /> 
} 

Обратите внимание, что ответ int? и может иметь значение между 0 и 5 (или null если пользователем еще не дал ответ). В идеале я бы хотел, чтобы это отображалось как радиокнопка для выбора возможных значений.

+0

Во-первых, вы не можете использовать 'foreach' цикл для создания элементов управления формы для сбора (см [этот ответ] (http://stackoverflow.com/questions/30094047/html-table-to -ado-нетто-DataTable/30094943 # 30094943)). Во-вторых, (я полагаю), вопрос будет иметь только один ответ, поэтому вы рассматриваете модель для «вопроса», должен иметь один «ответ», а не набор ответов «Ответ» –

+0

@StephenMuecke. В опросе есть список вопросов, но как может быть много случаев опроса, вопрос может иметь ответ в каждом опросе. Например, вопрос 1 в опросе 1 может иметь ответ 3, в то время как в другом опросе тот же вопрос может иметь ответ 7 – totalitarian

+0

В этом случае почему бы не использовать другой цикл foreach? –

ответ

1

Сначала вам нужно будет создать модель представления, представляющую вопрос и его ответ

public class QuestionVM 
{ 
    public int QuestionID { get; set; } 
    public string QuestionText { get; set; } 
    public int? AnswerID { get; set; } 
    [Range(0, 5)] 
    public int? Response { get; set; } 
} 

и основную модель представления будет (обратите внимание, что вид модели не должны содержать свойства, модели данных при редактировании)

public class SurveyResponseVM 
{ 
    public int ID { get; set; } // this will be bound by the route value 
    [Required(ErrorMessage = "Please select an area")] 
    [Display(Name = "Area")] 
    public int? SelectedArea { get; set; } 
    public IEnumerable<SelectListItem> AreaList { get; set; } 
    .... // other properties of assessment that you need for the view 
    public List<QuestionVM> Questions { get; set; } 
} 

так что с точки зрения вы можете использовать

@model SurveyResponseVM 
.... 
@using (Html.BeginForm()) 
{ 
    @Html.DropDownListFor(m => m.SelectedArea, Model.AreaList) 
    .... 
    for(int i = 0; i < Model.Questions.Count; i++) 
    { 
     <h3>@Model.Questions[i].QuestionText</h3> 
     @Html.HiddenFor(m => m.Questions[i].AnswerID) 
     for (int j = 0; j < 6; j++) 
     { 
      <label> 
       @Html.RadioButtonFor(m => m.Questions[i].Resonse, j, new { id = "" }) 
       <span>@j</span> 
      </label> 
     } 
    } 
    <input type="submit" value="Save" /> 
} 

который разместит назад

public ActionResult Edit(SurveyResponseVM model) 

Для получения значения в методе GET, ваш второй запрос (db.Questions.Where(q => q.isActive) кажется ненужным, поскольку у вас уже есть коллекция Answer, связанную с Survey (каждый Answer содержит Question свойства. Ваш код может быть

Survey survey = db.Surveys.Find(id); 
if (survey == null) // check for null here 
{ 
    return HttpNotFound(); 
} 
IEnumerable<Area> areas = db.Areas; 
SurveyResponseVM model = new SurveyResponseVM() 
{ 
    ID = survey.ID, 
    SelectedArea = survey.AreaID, 
    .... // other properties of Survey as required for the view 
    AreaList = new SelectList(areas , "ID", "SubLevel"), 
    Questions = survey.Answers.Select(x => new QuestionVM() 
    { 
     QuestionText = x.Question.QuestionText, 
     AnswerID = x.ID, 
     Response = x.Response 
    }) 
}; 
return View(model); 
+0

Еще раз спасибо. Я включил это в свое приложение, и все работает гладко :) – totalitarian

+1

Это действительно зависит от вас. Ввод кода для сопоставления модели данных в модель представления в отдельной службе (или с помощью таких инструментов, как [automapper] (http://automapper.org/)) делает ваш код контроллера более чистым и его предпочтение. Обычно я использую нечто вроде 'MyViewModel model = Map (dataModel); 'ConfigureViewModel (model);' where 'Map() 'возвращает модель представления на основе модели данных, а' ConfigureViewModel() 'создает' SelectList'' –

Смежные вопросы