具有多个实体的模型绑定
本文关键字:模型 绑定 实体 | 更新日期: 2023-09-27 18:32:51
我正在开发一个管理面板,该面板将允许用户添加一个或多个其他用户。有一个文本区域,管理员可以在其中输入一个或多个要添加到应用程序的用户 ID,这与在就业过程中分配的用户 ID 相对应。提交后,应用程序从包含所有员工的数据库中提取姓名、电子邮件等,并将其显示在屏幕上进行验证。屏幕上还包括一些用于分配某些权限的复选框,例如 CanWrite
和 IsAdmin
.
视图
using (Html.BeginForm())
{
<table>
<tr>
<th>
</th>
<th>
@Html.DisplayNameFor(model => model.User.First().ID)
</th>
<th>
@Html.DisplayNameFor(model => model.User.First().Name)
</th>
<th>
@Html.DisplayNameFor(model => model.User.First().Email)
</th>
<th>
@Html.DisplayNameFor(model => model.User.First().CanWrite)
</th>
<th>
@Html.DisplayNameFor(model => model.User.First().IsAdmin)
</th>
</tr>
@foreach (var item in Model.User)
{
<tr>
<td>
<input type="checkbox" name="id" value="@item.ID" checked=checked/>
</td>
<td>
@Html.DisplayFor(modelItem => item.ID)
</td>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Email)
</td>
<td>
@Html.CheckBoxFor(modelItem => item.CanWrite)
</td>
<td>
@Html.CheckBoxFor(modelItem => item.IsAdmin)
</td>
</tr>
}
</table>
<input type="submit" />
}
注意:使用名称ID
复选框的原因是,在获取名称和其他信息后,您不打算添加的用户能够不添加用户,例如,您不打算添加的用户意外进入了 ID 列表。
型
public class User
{
public int ID { set; get; }
public string Name { set; get; }
public bool IsAdmin { set; get; }
public bool CanWrite { set; get; }
public string Email{ set; get; }
}
控制器
[HttpPost]
public ActionResult Create(IEnumerable<User> model)
{
//With this code, model shows up as null
}
对于单个用户,我知道我可以在控制器操作中使用User model
作为参数。如何调整此代码以处理一次添加的多个用户?这可能吗?
你走在正确的轨道上,杰夫。 你只需要稍微扩展一下你所拥有的东西。
首先,在操作中null
模型的原因是因为表单上输入字段的命名方式。 您的字段将按如下方式呈现:
<input id="item_CanWrite" name="item.CanWrite" type="checkbox" value="true" />
<input name="item.CanWrite" type="hidden" value="false" />
请注意,name
item.CanWrite
。 这里的问题是,由于您循环访问了模型中的所有用户,因此您实际上为所有输入字段指定了相同的名称。 这会阻止 MVC 对绑定到 POST 数据进行建模,因为它无法区分每个User
。
为了解决这个问题,你需要将调用更改为Html.DisplayFor
,以便允许MVC将每个User
作为一个单独的实体来处理,从而允许每个User
的字段集按顺序命名。 这允许模型绑定程序正确绑定到这些字段。 这样:
@for (int i = 0; i < Model.Count(); i++)
{
<tr>
<td>
<input type="checkbox" name="id" value="@Model[i].ID" checked=checked/>
</td>
<td>
@Html.DisplayFor(m => m[i].ID)
</td>
<td>
@Html.DisplayFor(m => m[i].Name)
</td>
<td>
@Html.DisplayFor(m => m[i].Email)
</td>
<td>
@Html.CheckBoxFor(m => m[i].CanWrite)
</td>
<td>
@Html.CheckBoxFor(m => m[i].IsAdmin)
</td>
</tr>
}
如果您现在检查这些字段如何呈现为 HTML,您将看到它们看起来像这样:
<input checked="checked" data-val="true" data-val-required="The CanWrite field is required." name="[0].CanWrite" type="checkbox" value="true" />
<input name="[0].CanWrite" type="hidden" value="false" />
<input checked="checked" data-val="true" data-val-required="The CanWrite field is required." name="[1].CanWrite" type="checkbox" value="true" />
<input name="[1].CanWrite" type="hidden" value="false" />
如您所见,每个User
都有自己单独的索引。 我使用以下控制器方法使用了一个简单的测试设置,该方法在我的测试模型中选取了正确数量的记录:
[HttpPost]
public ActionResult Index(IEnumerable<User> model)
{
// Process your data.
return View(model);
}
但是,我想在这里提出进一步的改进建议,以消除您认为的逻辑。 为此,我们可以使用DisplayTemplates
而不是循环:
- 在视图的当前文件夹中创建一个
DisplayTemplates
文件夹(例如,如果您的视图Home'Index.cshtml
,请创建文件夹Home'DisplayTemplates
(。 - 在该目录中创建一个与您的模型匹配的名称的强类型视图(即在这种情况下,视图将称为
User.cshtml
(。 - 将重复的逻辑放在视图中。
您的模板现在应如下所示(不包括User
模型所在的命名空间(:
@model User
<tr>
<td>
<input type="checkbox" name="id" value="@Model.ID" checked=checked/>
</td>
<td>
@Html.DisplayFor(m => m.ID)
</td>
<td>
@Html.DisplayFor(m => m.Name)
</td>
<td>
@Html.DisplayFor(m => m.Email)
</td>
<td>
@Html.CheckBoxFor(m => m.CanWrite)
</td>
<td>
@Html.CheckBoxFor(m => m.IsAdmin)
</td>
</tr>
现在,在原始视图中,您可以将所有循环替换为以下内容:
@using (Html.BeginForm())
{
<table>
@Html.DisplayForModel()
</table>
<input type="submit" value="Submit" />
}
如果您想了解有关绑定到集合的更多信息,请参阅我为另一个问题提供的答案。
我才刚刚开始 ASP.NET MVC,但我想你只需要创建一个视图模型类,该类具有 IEnumerable<User>
类型的属性,用于存储用户集合。然后将其传递给您的视图并返回到您的POST
处理程序。
尝试这样的事情:
型
public class Employee
{
public IEnumerable<User> Employees { set; get; }
}
public class User
{
public int ID { set; get; }
public string Name { set; get; }
public bool IsAdmin { set; get; }
public bool CanWrite { set; get; }
public string Email{ set; get; }
}
视图
@model Employee
@using( Html.BeginForm()
{
// build HTML table, not much different from yours
}
控制器
[HttpPost]
public ActionResult Create(Employee model)
{
// model will have an IEnumerable property with the User info
}