在发布到服务器时,mvc中的所有复杂类型集合都为null

时间:2014-11-06 16:00:21

标签: asp.net-mvc

我对MVC很新,但正在取得进展。 我遇到了一个我似乎无法解决的问题,并且会对任何帮助都很满意。

当我发布到服务器时,我的编辑(在RoutineViewModel中)大部分丢失,原始数据类型被保留(在类Routine中)但复杂类型(ICollection<RoutineExercise>)的集合丢失。

我找到了这个MVC Form not able to post List of objects并按照建议将视图分成了一个EditorTemplate,但这没有用。在viewource时,使用“@foreach”循环仍会生成具有相同ID和名称的所有页面控件。我尝试使用for (int i = 1; i <= 5; i++)类型的循环,因为许多其他帖子建议但是会收到有关无法将索引应用于我的对象的错误。

@Html.DropDownListFor(model => Model.ExerciseId, Model.Exercises, "", new { @class = "input-sm col-md-12" })未选择正确的列表项(Model.ExerciseId具有正确的值)这一事实也让我感到担忧。

任何帮助/建议都会很棒,因为我已经被困住了3天了。

* POCO *

public partial class Routine
    {
        public Routine()
        {
            this.RoutineExercises = new List<RoutineExercise>();
        }

        public int Id { get; set; }
        public string RoutineName { get; set; }
        public string Description { get; set; }

        ...Other fields removed for clarity...

        public virtual ICollection<RoutineExercise> RoutineExercises { get; set; }
    }



 public partial class RoutineExercise
    {
        public int Id { get; set; }
        public int RoutineId { get; set; }
        public int Exerciseid { get; set; }
        public int SetsToDo { get; set; }
        public int RepsToDo { get; set; }

    ...Other fields removed for clarity...

        public virtual Exercise Exercise { get; set; } 
        public virtual Routine Routine { get; set; }
    }

* VIEWMODEL *

public class RoutineViewModel
    {      
    //Routine information  
        public int Id { get; set; }
        [Display(Name = "Name")]
        public string RoutineName { get; set; }
        public string Description { get; set; }                                    

    //Exercise information
        [Display(Name = "Exercise")]
        public ICollection<RoutineExercise> RoutineExercises { get; set; }
        public IEnumerable<SelectListItem> Exercises { get; set; }
        public int ExerciseId { get; set; }        

    }

* FORM *

<div class="panel-body">
    @using (Html.BeginForm("Edit", "Workout"))
    {
        @Html.AntiForgeryToken()

        <div class="form-horizontal">        

            @Html.ValidationSummary(true)
            @Html.HiddenFor(model => model.Id)
            @Html.EditorForModel()

            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <input type="submit" value="Save" class="btn btn-default" />
                </div>
            </div>
        </div>
    }
    <div>
        @Html.ActionLink("Back to List", "Index")
    </div>
</div>

* EDITOR TEMPLATE *

<div class="form-group">
    @Html.LabelFor(model => model.RoutineName, new { @class = "control-label col-md-1" })
    <div class="col-md-2">
        @Html.EditorFor(model => model.RoutineName)
        @Html.ValidationMessageFor(model => model.RoutineName)
    </div>

    @Html.LabelFor(model => model.Description, new { @class = "control-label col-md-1" })
    <div class="col-md-2">
        @Html.EditorFor(model => model.Description)
        @Html.ValidationMessageFor(model => model.Description)
    </div>   
</div>

@foreach (var e in Model.RoutineExercises)
{                                                                                               
    @Html.LabelFor(model => model.RoutineExercises, new { @class = "control-label col-md-1" })                                                          
    <div class="col-md-3">
       @*TO FIX This does NOT bind the selected value*@
       @Html.DropDownListFor(model => Model.ExerciseId, Model.Exercises, "", new { @class = "input-sm col-md-12" })
    </div>                                                 
    <div class="col-md-12">
        @Html.LabelFor(model => e.SetsToDo, new { @class = "control-label col-md-2" })
        @Html.EditorFor(m => e.SetsToDo, new { @class = "control-label col-md-10" })
    </div>    
}

* CONTROLLER *

[HttpPost]
        [ValidateAntiForgeryToken]                        
        public ActionResult Edit(RoutineViewModel rvm) /*rvm always null for collections only*/
        {
            if (ModelState.IsValid)
            {
                //Save Routine
                var r = new Routine
                {
                    Id = rvm.Id,
                    RoutineName = rvm.RoutineName,
                    Description = rvm.Description,
                    RoutineFrequencyId = rvm.RoutineFrequencyId,
                    RoutineLengthId = rvm.RoutineLengthId                                        
                };

                _repo.Update(r);

                return RedirectToAction("Index");
            }

            return View(getRoutineViewModel(rvm.Id));           
        }

1 个答案:

答案 0 :(得分:0)

首先,避免使用术语“复杂类型”,除非您实际上是在讨论实体框架中的复杂类型。它只会造成混乱,老实说,无论如何,你在这里所做的一切都非常“复杂”。

您确实需要使用带有索引而不是for的{​​{1}}循环来获取要使用的模型绑定器的正确字段名称。但是,您收到错误的原因是foreach不可订阅(ICollection)。您可以使用[N]在索引处提取项目,但遗憾的是,Razor仍然无法使用该名称创建正确的字段名称。因此,您需要为集合属性使用ElementAt(N)之类的内容来对其进行内联编辑。由于您已经在使用视图模型,因此这是微不足道的。只需在视图模型上将属性类型从List更改为ICollection<RoutineExcercise>即可。