Как я могу перемещаться по нескольким классам / таблицам в MVC с помощью внешних ключей?

Другими словами, как я могу пройти через «иерархическое дерево» моих классов через внешние ключи?

Ниже представлена картинка дерева и ассоциаций.

Вот краткая картина дерева и ассоциаций.

Я хочу, чтобы цикл через таблицы в моем представлении соответственно. Легко отобразить данные опроса и данные категории, потому что я могу просто ссылаться на PK и FK SurveyID из строки запроса. Я не уверен, как получить ассоциацию от CategoryID к SurveyID, хотя мимо этой точки.

Вот мой взгляд

@using (Html.BeginForm("Save", "Surveys"))
{

<div class="form-group">
    @Html.LabelFor(m => m.SurveyId)
    @Html.TextBoxFor(m => m.Description, new { @class = "form-control" })
    @Html.ValidationMessageFor(m => m.Description)
</div>
<div class="form-group">
            @for (int i = 0; i < Model.Categories.Count; i++)
            {
                <ul>@Html.TextBoxFor(m => m.Categories[i].Description, new { @class = "form-control" })</ul>
                @Html.HiddenFor(m => m.Categories[i].CategoryId)
                @*Here is where I attempted to loop the questions based on category*@
                @*@for (int j = 0; j < Model.Categories[i].Questions.Count(); j++)*@
                {
                    @Html.TextBoxFor(m => m.Questions[j].QuestionText)
                }
            }
</div>

    @Html.HiddenFor(m => m.User.Id)
    @Html.HiddenFor(m => m.SurveyId)
    @Html.AntiForgeryToken()
    <button type="submit" class="btn btn-primary">Save</button>
}

Я попробовал использовать for (int j = 0; j Вопросы.Count (); j++)

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

Моя догадка заключается в том, что проблема лежит не в представлении, а в контроллере о том, как он захватывает данные.

public ActionResult Edit(int id)
    {
        var survey = _context.Surveys.SingleOrDefault(c => c.SurveyId == id);
        var categories = new List<Category>();
        categories = _context.Categories.Where(c => c.SurveyId == id).ToList();
        var questions = new List<Question>();
        //questions = _context.Questions.Include()

        //var questions = new List<Question>();
        //questions = _context.Categories.Include(c => c.SurveyId == id).ToList();
        if (survey == null)
            return HttpNotFound();

        var viewModel = new NewSurveyViewModel(survey)
        {
            Questions = questions,
            Categories = categories
        };
        return View("SurveyForm", viewModel);
    }

Здесь я не уверен, должен ли я использовать метод include или что, но я не могу думать о том, как соединить связь между категорией и идентификаторами опроса, а затем оттуда перейти к использованию QuestionID.

Я относительно близок?

3 ответа

  1. Это выглядит как проблема доступа к данным, а не проблема MVC. Если вы используете Entity Framework, Entity Framework загружает связанные сущности, чтобы обеспечить загрузку объектов.

    Кроме того, не загружайте вопросы в viewModel отдельно, так как необходимо сохранить иерархию. Ваш TextBoxFor вызов для вопросов должен использовать это.

    Попробуйте @Html.TextBoxFor(m => m.Categories[i].Questions[j].QuestionText).

  2. JamieSee отметил, что для того, чтобы получить данные, чтобы показать, сначала нетерпеливый загрузки должны использоваться, как показано здесь msdn.microsoft.com/en-us/library/jj574232 (v=против 113).aspx

    затем я использовал вложенный цикл foreach.

    <div class="form-group">
        @foreach (var category in Model.Categories.Where(q => q.SurveyId == Model.SurveyId))
        {
            <ul>@Html.TextBoxFor(m => category.Description, new { @class = "form-control" })</ul>
                @Html.HiddenFor(m => category.CategoryId)
    
            foreach (var question in Model.Questions.Where(q => q.CategoryId == category.CategoryId))
            {
                <ul>@Html.TextBoxFor(m => question.QuestionText, new { @class = "form-control" })</ul>
                    @Html.HiddenFor(m => question.QuestionId)
    
                foreach (var answer in Model.Answers.Where(a => a.QuestionId == question.QuestionId))
                {
                    <ul>@Html.TextBoxFor(m => answer.AnswerText, new { @class = "form-control" })</ul>
                        @Html.HiddenFor(m => answer.AnswerId)
                }
            }
        }
    </div>
    
  3. var db = new DBContext() // => this is your database context
    
    var result = from s in db.Surveys
                 select new {
                   survey = s,
                   categories = from c in db.Categories
                                where c.SurveyID = s.ID
                                select new {
                                   category = c,
                                   questions = from q in db.Questions
                                               where q.CategoryID = c.ID
                                               select new {
                                                   question = q,
                                                   answers = from a in db.Answers
                                                             where a.QuestionID = q.ID
                                                             select a
                                                } // close the questions
                                } // close the categories
                };// close the surveys
    
    return result;
    

    Если вы хотите использовать этот запрос внутри представления, вы можете использовать с out return result;
    Также вам не нужно определять класс передачи данных.

    Но если вы хотите использовать внутри контроллера и возвращать из любого действия или результата json; вы должны использовать объект класса для передачи данных на каждом уровне select.

    Например, класс DTO первого уровня может быть таким;

    public class SurveyDTO
    {
        public Survey survey{get;set;}
        public List<CategoriesDTO> categories {get;set;}
    }
    

    И второй уровень DTO;

    public class CategoriesDTO
    {
        public Category category {get;set;}
        public List<QuestionsDTO> questions {get;set;}
    }
    

    Так же третий уровень;

    public class QuestionsDTO
    {
        public Question question {get;set;}
        public List<Answer> answers{get;set;}
    }
    

    Не забудьте добавить имена DTO после выбора! В contreller; запрос изменяется следующим образом;

    var db = new DBContext() // => this is your database context
    
    var result = (from s in db.Surveys
                 select new SurveyDTO(){
                   survey = s,
                   categories = (from c in db.Categories
                                where c.SurveyID = s.ID
                                select new CategoriesDTO(){
                                   category = c,
                                   questions = (from q in db.Questions
                                               where q.CategoryID = c.ID
                                               select new QuestionsDTO(){
                                                   question = q,
                                                   answers = (from a in db.Answers
                                                             where a.QuestionID = q.ID
                                                             select a).ToList()
                                                }).ToList() // close the questions
                                }).ToList() // close the categories
                }).ToList();// close the surveys
    
    return result;
    

    Надеюсь объяснение понятное и поможет.

    ЕСЛИ ВЫ ИСПОЛЬЗУЕТЕ ОДИН ЗАПРОС ДЛЯ ПОЛУЧЕНИЯ ДАННЫХ, ЭТО БУДЕТ БЫСТРЕЕ