基于ViewModel多表过滤:按AddCustomersID实现客户专属模态框
解决Razor视图中模态框仅显示对应客户信息的问题
嘿,我看你现在的问题是每个客户的模态框里都显示了所有员工和联系信息,而不是只对应当前客户的数据对吧?其实最靠谱的方案就是在Razor的@foreach循环里直接做过滤,或者更好的是提前在后端把数据关联好,完全不用绕JavaScript,逻辑清晰还更高效。
方案一:直接在视图中过滤数据(快速修复)
你当前的问题核心是内部循环没有做筛选——@foreach (var item in Model.EmployeeInfo)遍历了所有员工记录,所以每个模态框都显示全量数据。只要在内部循环时,只保留AddCustomersID和当前客户ID匹配的记录就行。
修改后的视图代码:
@model Intranet.ViewModels.IntranetViewModel @foreach (var customer in Model.AddCustomers) { <div class="modal"> <h2>@Html.DisplayFor(modelItem => customer.CompanyName)</h2> <table> <tr> <th>Company Name</th> <th>Forename</th> <th>Surname</th> <th>Title</th> <th>Mobile</th> <th>Telephone</th> <th>Email</th> </tr> @* 过滤出当前客户的员工信息 *@ @foreach (var employee in Model.EmployeeInfo.Where(e => e.AddCustomersID == customer.AddCustomersID)) { <tr> <td> @Html.DisplayFor(modelItem => employee.AddCustomers.CompanyName) </td> <td> @Html.DisplayFor(modelItem => employee.Forename) </td> <td> @Html.DisplayFor(modelItem => employee.Surname) </td> <td> @Html.DisplayFor(modelItem => employee.Title) </td> <td> @Html.DisplayFor(modelItem => employee.Mobile) </td> <td> @Html.DisplayFor(modelItem => employee.Telephone) </td> <td> @Html.DisplayFor(modelItem => employee.Email) </td> </tr> } </table> <table> <tr> <th>Company Name</th> <th>Code</th> <th>Address</th> <th>Postcode</th> <th>Telephone</th> </tr> @* 同样过滤当前客户的联系信息 *@ @foreach (var contact in Model.ContactInfo.Where(c => c.AddCustomersID == customer.AddCustomersID)) { <tr> <td> @Html.DisplayFor(modelItem => contact.AddCustomers.CompanyName) </td> <td> @Html.DisplayFor(modelItem => contact.Code) </td> <td> @Html.DisplayFor(modelItem => contact.Address) </td> <td> @Html.DisplayFor(modelItem => contact.Postcode) </td> <td> @Html.DisplayFor(modelItem => contact.Telephone) </td> </tr> } </table> ... </div> }
我把外部循环的变量名改成了customer,避免和内部循环的item重名,代码可读性更好。
方案二:优化后端关联数据(更推荐)
如果你的数据量比较大,视图里每次用Where过滤会有性能损耗,而且代码不够简洁。最好的方式是让AddCustomers模型直接关联对应的员工和联系信息,然后在控制器里提前加载这些关联数据。
1. 修改AddCustomers模型(添加关联)
public class AddCustomers { public int AddCustomersID { get; set; } public string CompanyName { get; set; } // 关联当前客户的所有员工 public ICollection<EmployeeInfo> EmployeeInfo { get; set; } // 关联当前客户的所有联系信息 public ICollection<ContactInfo> ContactInfo { get; set; } }
2. 更新ViewModel(简化结构)
其实如果只是展示客户及其关联数据,甚至可以直接传递IEnumerable<AddCustomers>,但如果需要其他额外数据,保留ViewModel即可:
namespace Intranet.ViewModels { public class IntranetViewModel { public IntranetViewModel() { AddCustomers = new List<AddCustomers>(); } public int IntranetViewModelID { get; set;} // 这里的AddCustomers已经包含对应的子数据 public IEnumerable<AddCustomers> AddCustomers { get; set; } ... } }
3. 控制器中提前加载关联数据
用EF的Include方法提前加载关联数据,避免延迟加载带来的多次数据库查询:
private IntranetContext db = new IntranetContext(); public ActionResult Index() { var viewModel = new IntranetViewModel { // 一次性加载客户及其关联的员工、联系信息 AddCustomers = db.AddCustomers .Include(c => c.EmployeeInfo) .Include(c => c.ContactInfo), ... }; return View(viewModel); }
4. 简化视图代码
现在视图里直接取当前客户的子集合就行,完全不用过滤:
@model Intranet.ViewModels.IntranetViewModel @foreach (var customer in Model.AddCustomers) { <div class="modal"> <h2>@Html.DisplayFor(modelItem => customer.CompanyName)</h2> <table> <tr> <th>Company Name</th> <th>Forename</th> <th>Surname</th> <th>Title</th> <th>Mobile</th> <th>Telephone</th> <th>Email</th> </tr> @foreach (var employee in customer.EmployeeInfo) { <tr> <td> @Html.DisplayFor(modelItem => customer.CompanyName) </td> <td> @Html.DisplayFor(modelItem => employee.Forename) </td> <td> @Html.DisplayFor(modelItem => employee.Surname) </td> <td> @Html.DisplayFor(modelItem => employee.Title) </td> <td> @Html.DisplayFor(modelItem => employee.Mobile) </td> <td> @Html.DisplayFor(modelItem => employee.Telephone) </td> <td> @Html.DisplayFor(modelItem => employee.Email) </td> </tr> } </table> <table> <tr> <th>Company Name</th> <th>Code</th> <th>Address</th> <th>Postcode</th> <th>Telephone</th> </tr> @foreach (var contact in customer.ContactInfo) { <tr> <td> @Html.DisplayFor(modelItem => customer.CompanyName) </td> <td> @Html.DisplayFor(modelItem => contact.Code) </td> <td> @Html.DisplayFor(modelItem => contact.Address) </td> <td> @Html.DisplayFor(modelItem => contact.Postcode) </td> <td> @Html.DisplayFor(modelItem => contact.Telephone) </td> </tr> } </table> ... </div> }
为什么不推荐JavaScript方案?
你之前尝试的JS过滤确实会遇到多元素选择的问题,而且把所有客户的数据都渲染到页面上再过滤,不仅页面加载慢,还存在数据泄露风险——用户可以通过查看源码看到所有客户的信息。后端提前关联或过滤数据才是更安全、高效的做法。
内容的提问来源于stack exchange,提问作者Riley
相关产品推荐
相关产品推荐

