You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Database First场景下View返回Person的Roles列表为空如何修复

问题成因

  1. 模型绑定过滤了Roles属性:你在Post的Edit方法中用[Bind(Include = "id,nachname,vorname,winLogon")]限定了只绑定这4个字段,导航属性Roles直接被模型绑定器忽略,所以Post拿到的person对象的Roles属性默认是空集合。
  2. 导航属性未预加载:Get请求的Edit方法中用FindAsync查Person时,没有用Include(p => p.Roles)预加载关联的角色数据,如果你关闭了EF的懒加载,那Get返回的Person的Roles本身就为空。
  3. View代码存在语法错误:
    • 循环条件写的是i < Model.Roles,直接把集合当数值判断,应该取集合的数量i < Model.Roles.Count()
    • 循环内没有定义role变量,直接使用会报错
    • DropDownListFor绑定对象错误,直接绑定整个Roles集合,而不是单个角色的id
  4. Post返回View时未重填ViewBag:Post请求的Edit方法中,操作完返回View时没有重新给ViewBag.allRoles赋值,View拿到的allRoles为空,下拉框无法正常渲染。
  5. 代码存在多处笔误:
    • 角色类的类名是Rolle,但代码里多处写成Role,拼写不一致
    • Save逻辑里的userRoles变量未定义,属于无效代码

修复方案

1. 调整Controller逻辑

首先修改Get的Edit方法,预加载Roles:

public async Task<ActionResult> Edit(int? id)
{
    if (id == null)
    {
        return RedirectToAction("BadRequest", "Error", new { area = "" });
    }
    // 预加载关联的Roles
    Person person = await db.Person.Include(p => p.Roles).FirstOrDefaultAsync(p => p.id == id);
    if (person == null)
    {
        return RedirectToAction("NotFound", "Error", new { area = "" });
    }
    ViewBag.allRoles = db.Roles.ToList();
    return View(person);
}

然后修改Post的Edit方法,优先从数据库取最新的Person数据操作,避免模型绑定的导航属性为空:

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = "id,nachname,vorname,winLogon")] Person person, string command, int? roleId)
{
    // 先从数据库查带Roles的真实实例
    var dbPerson = await db.Person.Include(p => p.Roles).FirstOrDefaultAsync(p => p.id == person.id);
    if (dbPerson == null)
    {
        return RedirectToAction("NotFound", "Error", new { area = "" });
    }
    // 同步基础字段
    dbPerson.nachname = person.nachname;
    dbPerson.vorname = person.vorname;
    dbPerson.winLogon = person.winLogon;

    Rolle none = new Rolle { id = -1, name = "None" };
    var allRoles = db.Roles.ToList();
    // 重填ViewBag
    ViewBag.allRoles = allRoles;

    if (ModelState.IsValid)
    {
        if (command == "remove" && roleId.HasValue)
        {
            var toRemove = dbPerson.Roles.FirstOrDefault(x => x.id == roleId);
            if(toRemove != null) dbPerson.Roles.Remove(toRemove);
            return View(dbPerson);
        }

        if (command == "add")
        {
            dbPerson.Roles.Add(none);
            return View(dbPerson);
        }

        if (command == "save")
        {
            // 移除临时的none角色
            var tempNone = dbPerson.Roles.FirstOrDefault(r => r.id == -1);
            if(tempNone != null) dbPerson.Roles.Remove(tempNone);
            // 标记实体为修改状态
            db.Entry(dbPerson).State = EntityState.Modified;
            await db.SaveChangesAsync();
            return RedirectToAction("Index");
        }
    }
    return View(dbPerson);
}

2. 修正View代码

@model Models.Person
@{
    ViewBag.Title = "Edit";
    List<Rolle> allRoles = ViewBag.allRoles;
}

<h2>Edit</h2>

@using (Html.BeginForm("Edit", "People", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    @Html.AntiForgeryToken()
    <div class="form-horizontal">
        <h4>Person</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        @Html.HiddenFor(model => model.id)

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

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

        <div class="form-group col-md">
            @for (int i = 0; i < Model.Roles.Count(); i++)
            {
                var role = Model.Roles.ElementAt(i);
                @Html.LabelFor(model => model.Roles, new { @class = "control-label col-md-2" })
                <div class="col-md-10">
                    @Html.DropDownListFor(model => model.Roles.ElementAt(i).id, new SelectList(allRoles, "id", "name", role.id), new { @class = "form-control-static col-md-1" })
                    <input type="hidden" name="roleId" value="@role.id" />
                    <input name="command" type="submit" value="remove" class="btn btn-default col-md-offset-1" />
                </div>
            }

            <input name="command" type="submit" value="add" class="btn btn-default col-md-offset-1" />
        </div>


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

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

3. 统一命名

要么把角色类名从Rolle改成Role,要么把代码里所有用到Role的地方都改成Rolle,避免拼写错误导致的编译异常。


内容的提问来源于stack exchange,提问作者Pablu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 11:06:04