【问题标题】:MVC5 ModelView is not valid on post of edit actionMVC5 ModelView 在编辑操作后无效
【发布时间】:2015-05-28 15:32:27
【问题描述】:

我有一个带有 Entity 6 框架的 MVC5 项目,我无法将正确的信息传递给帖子的编辑操作,以便将其绑定到模型。我的 viewModel 的 ModelState 返回无效。我不确定我错过了什么。我猜这与我的编辑器模板的设置方式与模型的结构有关,但我需要一些帮助来弄清楚。我花了很多时间来改变一些东西来尝试让它工作,但我仍然无法纠正它。

我的视图模型:

namespace CommunityHealth.Models.ViewModels
{
    public class ActivityViewModel
    {
        public virtual IList<JunctionTypeAction> junctionTypeActions{ get; set; }
        public virtual IList<JunctionDepartmentAction> junctionDepartmentActions{ get; set; }
        public virtual IList<JunctionPopulationAction> junctionPopulationActions { get; set; }
        public virtual CommunityAction Action { get; set; }
    }
}

社区行动模型:

public partial class CommunityAction
{
    public CommunityAction()
    {
        this.JunctionPopulationActions = new HashSet<JunctionPopulationAction>();
        this.JunctionDepartmentActions = new HashSet<JunctionDepartmentAction>();
        this.JunctionTypeActions = new HashSet<JunctionTypeAction>();
    }

    public int ActionID { get; set; }
    public System.DateTime StartDate { get; set; }
    public Nullable<System.DateTime> EndDate { get; set; }
    public string BreifDescription { get; set; }
    public Nullable<int> Duration { get; set; }
    public int LocationID { get; set; }
    public string SubLocation { get; set; }
    public int ProgramID { get; set; }
    public string Notes { get; set; }
    public string AddedBy { get; set; }
    public byte[] RecordVersion { get; set; }

    public virtual Location Location { get; set; }
    public virtual Program Program { get; set; }
    public virtual ICollection<JunctionPopulationAction> JunctionPopulationActions { get; set; }
    public virtual ICollection<JunctionDepartmentAction> JunctionDepartmentActions { get; set; }
    public virtual ICollection<JunctionTypeAction> JunctionTypeActions { get; set; }
}

连接表的模型: JunctionDepartmentAction:

public partial class JunctionDepartmentAction
{
    public int IndexID { get; set; }
    public int DepartmentID { get; set; }
    public int ActionID { get; set; }
    public string SubDepartment { get; set; }
    public int Individuals { get; set; }

    public virtual CommunityAction CommunityAction { get; set; }
    public virtual Department Department { get; set; }
}

JunctionPopulationAction:

public partial class JunctionPopulationAction
{
    public int IndexID { get; set; }
    public int PopulationID { get; set; }
    public int ActionID { get; set; }
    public bool isActive { get; set; }
    public virtual CommunityAction CommunityAction { get; set; }
    public virtual TargetPopulation TargetPopulation { get; set; }
}

JunctionTypeAction:

public partial class JunctionTypeAction
{
    public int IndexID { get; set; }
    public int TypeID { get; set; }
    public int ActionID { get; set; }
    public virtual ActivityType ActivityType { get; set; }
    public virtual CommunityAction CommunityAction { get; set; }
}

事件控制器编辑动作方法:

// GET: /Event/Edit/5
    public async Task<ActionResult> Edit(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        CommunityAction communityaction = await db.CommunityActions.FindAsync(id);
        ActivityViewModel activityviewmodel = new ActivityViewModel();
        activityviewmodel.Action = communityaction;
        IList<JunctionTypeAction> junctiontypeactions = await db.JunctionTypeActions.Where(d => d.ActionID == communityaction.ActionID).ToListAsync();
        IList<JunctionDepartmentAction> junctiondepartmentactions = await db.JunctionDepartmentActions.Where(d => d.ActionID == communityaction.ActionID).ToListAsync();
        IList<JunctionPopulationAction> junctionpopulationactions = await db.JunctionPopulationActions.Where(d => d.ActionID == communityaction.ActionID).ToListAsync();
        activityviewmodel.junctionTypeActions = junctiontypeactions.ToList();
        activityviewmodel.junctionDepartmentActions = junctiondepartmentactions.ToList();
        activityviewmodel.junctionPopulationActions = junctionpopulationactions.ToList();            
        if (communityaction == null)
        {
            return HttpNotFound();
        }
        ViewBag.LocationID = new SelectList(db.Locations, "LocationID", "LocationName", activityviewmodel.Action.LocationID);
        ViewBag.ProgramID = new SelectList(db.Programs, "ProgramID", "ProgramID", activityviewmodel.Action.ProgramID);
        return View(activityviewmodel);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Edit(ActivityViewModel activity)
    {
        //request added for debugging purposes
        Request.ToString();
        if (ModelState.IsValid)
        {
            db.Entry(activity).State = EntityState.Modified;
            await db.SaveChangesAsync();
            return RedirectToAction("Index");
        }
        ViewBag.LocationID = new SelectList(db.Locations, "LocationID", "LocationName", activity.Action.LocationID);
        ViewBag.ProgramID = new SelectList(db.Programs, "ProgramID", "ProgramID", activity.Action.ProgramID);
        return View(activity);
    }

最后是我的观点。我为数据库中的联结表使用了三个编辑器模板,为 CommunityAction 对象使用了另外一个。然后我有一个事件视图,它使用三个编辑器模板来显示 ViewModel 的各个部分。

CommunityAction.cshtml:

@model CommunityHealth.Models.CommunityAction
<div class="form-horizontal">
<h4>CommunityAction</h4>
<hr />
@Html.ValidationSummary(true)
@Html.HiddenFor(model => model.ActionID)
@Html.HiddenFor(model => model.RecordVersion)
<div class="form-group">
    @Html.LabelFor(model => model.StartDate, new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.StartDate)
        @Html.ValidationMessageFor(model => model.StartDate)
    </div>
</div>
<div class="form-group">
    @Html.LabelFor(model => model.EndDate, new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.EndDate)
        @Html.ValidationMessageFor(model => model.EndDate)
    </div>
</div>
<div class="form-group">
    @Html.LabelFor(model => model.BreifDescription, new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.BreifDescription)
        @Html.ValidationMessageFor(model => model.BreifDescription)
    </div>
</div>

<div class="form-group">
    @Html.LabelFor(model => model.Duration, new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.Duration)
        @Html.ValidationMessageFor(model => model.Duration)
    </div>
</div>
<div class="form-group">
    @Html.LabelFor(model => model.LocationID, "Location", new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.DropDownListFor(model => model.Location, ViewBag.LocationID as SelectList, new { htmlAttributes = new { @class = "control-form" } })
        @Html.ValidationMessageFor(model => model.Location)
    </div>
</div>

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

<div class="form-group">
    @Html.LabelFor(model => model.ProgramID, "Program", new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.DropDownListFor(model => model.ProgramID, ViewBag.ProgramID as SelectList, new { htmlAttributes = new { @class = "control-form" } })
        @Html.ValidationMessageFor(model => model.Program)
    </div>
</div>

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

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

JunctionTypeAction.cshtml:

@model CommunityHealth.Models.JunctionTypeAction
<div class="type">
<fieldset>
    @Html.HiddenFor(model => model.ActionID)
    @Html.HiddenFor(model => model.IndexID)
    @Html.EditorFor(model => model.TypeID, "TypeName", new { @class = "control-label col-md-2" })
</fieldset>
</div>

JunctionDepartmentAction.cshtml:

@model CommunityHealth.Models.JunctionDepartmentAction
@using CommunityHealth.Models
<div>
<table>
    <tbody>
        <tr>
            <td>
                @Html.HiddenFor(model => model.ActionID)
                @Html.HiddenFor(model => model.IndexID)
                @Html.EditorFor(model => model.DepartmentID, "DepartmentName", new { @class = "control-label col-md-2" })
            </td>
            <td>
                @Html.EditorFor(model => model.SubDepartment, "SubDepartment", new { @class = "control-label col-md-2 " })
            </td>
            <td>
                @Html.EditorFor(model => model.Individuals)
            </td>
        </tr>
    </tbody>
</table>
</div>

JunctionPopulationAction.cshtml:

@model CommunityHealth.Models.JunctionPopulationAction

<div class="population">
<fieldset>
    @Html.HiddenFor(model => model.ActionID)
    @Html.HiddenFor(model => model.IndexID)
    @Html.EditorFor(model => model.PopulationID, "PopulationName", new { @class = "control-label col-md-2" })
</fieldset>
</div>

视图\事件\Edit.cshtml:

@model CommunityHealth.Models.ViewModels.ActivityViewModel
@using CommunityHealth.Models.ViewModels;
@{
    ViewBag.Title = "Edit";
}
<h2>Edit</h2>
@using (Html.BeginForm("Edit","Event",FormMethod.Post))
{
    @Html.AntiForgeryToken()
    <div>
        <div class="form-group">
            @Html.EditorFor(model => model.Action)
        </div>
        <div class="form-group">
            @Html.Label("Types")
            <div class="col-md-10">
                <fieldset>
                    @for (int x = 0; x < Model.junctionTypeActions.Count(); x++)
                    {
                        @Html.EditorFor(model => model.junctionTypeActions[x])
                    }
                </fieldset>
            </div>
        </div>
        <div class="form-group">
            @Html.Label("Departments")
            <div class="col-md-10">
                @for (int x = 0; x < Model.junctionDepartmentActions.Count(); x++)
                {
                    @Html.EditorFor(model => model.junctionDepartmentActions[x])
                }
            </div>
        </div>
        <div class="form-group">
            @Html.Label("Target Populations")
            <div class="col-md-10">
                @for (int x = 0; x < Model.junctionDepartmentActions.Count(); x++)
                {
                   @Html.EditorFor(model => model.junctionPopulationActions[x])
                }
            </div>
        </div>
        <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>
}
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

我在检查请求时收到此错误:

“从类型 'System.String' 到类型 'CommunityHealth.Models.CommunityAction' 的参数转换失败,因为没有类型转换器可以在这些类型之间进行转换。”

【问题讨论】:

  • 回发的问题是什么 - 模型是否为空?模型的属性是否为空?收藏品没有绑定吗? (你真的希望任何人都涉足所有这些代码吗?) 注意:渲染所有这些隐藏的输入是不好的做法并且会降低性能 - 使用视图模型只表示你想要编辑的内容。只需使用@Html.EditorFor(m =&gt; m.junctionTypeActions) - 不在for 循环内
  • 感谢任何反馈。我当然不“期望”任何人提供帮助,我只是希望有人可以看看我错过了什么。如果有人确实选择调查我的问题,我希望他们拥有他们需要的一切,以找出我做错了什么。我不打算保留隐藏类型。我确实喜欢你有路口的方式,为了简单起见,我已经改为这种方式。
  • 你的模型不应该这么复杂......哎呀,为什么集合是虚拟的?这不是实体框架。通常没有理由让所有这些集合在视图模型中相互引用。
  • @ErikFunkenbusch 这些模型都是Entity framework 6 Data Entity Model生成的,除了我创建的视图模型?模型并不复杂。保存多对多关系数据的 SQL 联结表有三个模型,而 CommunityAction 的模型也是一个 SQL 表。虚拟属性用于保存与外键的关系。哈希集用于查找联结表中的相关项目。这都是有道理的,所以我不确定模型会出现什么问题。

标签: c# razor asp.net-mvc-5 entity-framework-6


【解决方案1】:

该错误的原因是因为您的模型有一个名为 activity 的属性(typeof CommunityAction),并且您的 post 方法的参数也命名为 activity。将参数名称更改为模型中属性名称以外的任何名称

public async Task<ActionResult> Edit(ActivityViewModel model)
{
  ....
}

附注

  1. 只需使用@Html.EditorFor(m =&gt; m.junctionTypeActions)即可生成 集合的 html(不在 for 循环中)。 @Html.EditorFor() 足够聪明,可以识别集合并生成正确的 html。
  2. 生成所有这些隐藏的输入是不好的做法并且会降级 性能(并且任何恶意用户都可以更改值)。 为每个类型或您的类型使用仅包含 您需要显示/编辑的属性。

【讨论】:

  • 这似乎让我克服了当前的障碍!我必须更改我的 CommunityAction 编辑器模板,以便它绑定到 LocationID 而不是 Location,但是一旦我更改了名称并且能够在断点处正确查看我的所有结果,这很容易找到。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2018-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-07
相关资源
最近更新 更多