为什么POST操作会丢失模型数值?

4
我有一个ViewModel,想要将其提交以便在数据库中保存。当ViewModel在//GET Create(int id)中获取值时,它会在到达//POST Create()时丢失部分值。虽然GoalLevelGoalTitle可以正常传递,但ActorIdProjectId则被丢失。尽管调试器经过了if (Model.State.IsValid)块,但是通过的值并没有保存到数据库中。重定向失败,因为我已经没有有效的ProjectId来传递到URL。

如果您知道该怎么做,我相信这是明显的问题!

控制器(Controller)

  // GET: UseCases/Create

    public ActionResult Create(int id)

    {

        ViewBag.projectId = id;

        //Populate the ViewModel
        UserGoalsStepViewModel model = new UserGoalsStepViewModel()
        {
            ProjectId = id,
            ActorList = new SelectList(db.Actors.Where(a => a.projectID == id), "id", "Title"),

        };

        return View(model);
    }

    // POST: UseCases/Create
    // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
    // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "ProjectId,ActorId,GoalTitle,Level")] UserGoalsStepViewModel model)
    {




        if (ModelState.IsValid)
        {

            //Create a use case object to map to, which can then be saved in the DB

            UseCase uc = new UseCase();
            uc.ProjectID = model.ProjectId;
            uc.ActorID = model.ActorId;
            uc.Level = (Level)model.Level;
            db.SaveChanges();
            return RedirectToAction("Index", new { id = model.ProjectId });
        }

        return View(model);
    }           

视图模型

 public class UserGoalsStepViewModel
    {
        public enum GoalLevel
        {
            Summary, UserGoal, SubGoal,
        }

            public int ProjectId { get; set; }
            public int ActorId { get; set; }
            [DisplayName("Actor Title")]    
            public SelectList ActorList { get; set; }
            [DisplayName("Goal Title")]
            public string GoalTitle { get; set; }
            public GoalLevel Level { get; set; }

            public UserGoalsStepViewModel ()
            {

            }


    }

查看

@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>UseCase</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

        <div class="form-group">
            @Html.LabelFor(model => model.ActorList, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownListFor(model => model.ActorList, Model.ActorList, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.ActorList, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.GoalTitle, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.GoalTitle, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.GoalTitle, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Level, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EnumDropDownListFor(model => model.Level, htmlAttributes: new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.Level, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

更新的POST方法仍然出现错误,无法保存到数据库

经过修改后,我现在遇到了这个错误Message=插入语句与外键约束“FK_dbo.UseCase_dbo.Actor_ActorID”冲突。该冲突发生在数据库“JustSpecIt”的表“dbo.Actor”中,列'ID',尝试保存到数据库时。

以下是更新的POST方法的相关部分:

if (ModelState.IsValid)
            {

                //Create a use case object to map to, which can then be saved in the DB

                UseCase uc = new UseCase();
                uc.ProjectID = model.ProjectId;
                uc.ActorID = model.ActorId;
                uc.Title = model.GoalTitle;
                uc.Level = (Level)model.Level;
                db.UseCases.Add(uc);
                db.SaveChanges();
                return RedirectToAction("Index", new { id = model.ProjectId });
            }
1个回答

7

您需要将ProjectId和ActorId的值作为隐藏输入存储在表单中,以便可以将它们包含在发送回控制器操作的发布值中。

 @using (Html.BeginForm()) 
 {
     @Html.AntiForgeryToken()
     @Html.HiddenFor(x => x.ProjectId)
     @Html.HiddenFor(x => x.ActorId)
     ...
 }

谢谢,这个方法很有用。我之前没有意识到如果视图中没有任何东西来保存模型值,那么在提交时它将会丢失- 给我上了一堂课!但是我还遇到了一个问题,就是在保存到数据库时出现了异常: Message=The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.UseCase_dbo.Actor_ActorID". The conflict occurred in database "JustSpecIt", table "dbo.Actor", column 'ID'。 我已经在上面的帖子中添加了更新。 - gazrolo4
实际上,我知道为什么会出现FK错误,因为ActorId仍未发布。我将进行进一步的调查 - 我怀疑这与SelectList有关。 - gazrolo4
1
之所以没有传递成功,是因为您的模型属性被称为ActorList,因此您传递给操作的不是名为ActorId的值,而是名为ActorList的值。 - mreyeros
你说得对 - 我的选择列表搞错了。实际上,我进行了一些重构,并在我的ViewModel中用SelectedActorId替换了ActorId,然后将DDL更改为@Html.DropDownListFor(model => model.SelectedActorId, Model.ActorList, new { @class = "form-control" }),并将我的POST操作更改为uc.ActorID = model.SelectedActorId; - gazrolo4
很好,我很高兴能够帮助您指明正确的方向。 - mreyeros

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接