ASP.Net 从多个表格中筛选下拉列表项
ASP.Net Filter Dropdown list items from multiple tables
总结:
我正在尝试使用两个 DropDownList 控件来筛选当前正在排序并显示在视图中的数据。
我们要学习什么
为可以使用 DropDownList
过滤数据的一对多和多对多关系创建 ViewController
可能的原因
如果我的 DropdownList 代码没有严重错误,那么我用来显示数据的 ViewModel 对 DropDownList 项目没有适当的支持。
换句话说,RazorView 和我的 ViewModel 与我想要实现的目标不兼容。如果我尝试更改我的 ViewModel 或 RazorView,我会收到现有代码的无限错误循环。
或者 Linq 查询需要专家的关注
这里是FilterViewModel.cs
public IEnumerable <App> Apps { get; set; }
public IEnumerable <Language> Languages { get; set; }
public IEnumerable <Platform> Platforms { get; set; }
public IEnumerable <AgeGroup> AgeGroups { get; set; }
public IEnumerable <ProductCode> ProductCodes { get; set; }
这里是AppsController.cs
public ActionResult FilterApps(App app)
{
var apps = _context.Apps.ToList();
var languages = _context.Languages.ToList();
var productCodes = _context.ProductCodes.ToList();
var platforms = _context.Platforms.ToList();
var ageGroups = _context.AgeGroups.ToList();
var viewModel = new FilterViewModel
{
AgeGroups = ageGroups,
Languages = languages,
Platforms = platforms,
ProductCodes = productCodes,
Apps = apps
.Where(a => a.LanguageId == app.LanguageId && a.PlatformId == app.PlatformId)
// I also tried all possible combinations :(a.Lanage.Id etc)
};
return View("FilterApps", viewModel);
}
这里是FilterApps.cshtml
@model Marketing.ViewModels.FilterViewModel
<h2>FilterApps</h2>
@using (Html.BeginForm("FilterApps", "Apps", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="form-group">
@Html.DropDownListFor( m => m.Languages,
new SelectList(Model.Languages, "Id", "Name"),"Select Language",
new { @class = "form-control", @id = "dropDown" })
@Html.DropDownListFor(m => m.Platforms,
new SelectList(Model.Platforms, "Id", "Name"), "Select Platform",
new { @onchange = "this.form.submit();",
@class = "form-control", @id = "dropDown" })
</div>
}
//The existing code below is working fine so far.
@foreach (var group in Model.AgeGroups)
{
<h4>@group.Name</h4>
@foreach (var app in Model.Apps.OrderBy(a => a.AppOrder))
{
if (app.AgeGroupId == group.Id)
{
@app.ProductCode.Name
@app.Name
@app.Platform.Name
}
}
}
可能没有必要,但我希望额外的信息能有所帮助。
附加信息
App.cs 正在引用所有其他表,例如
public Language Language { get; set; }
public int LanguageId { get; set; }
public Platform Platform { get; set; }
public int PlatformId { get; set; }
and so on...
我已经尝试过的
几个断点和日志来跟踪数据,我也尝试使用以下但它破坏了我现有的排序和分组。
public App App { get; set; } //Instead of the IEnumerable<App>
您的代码存在多个问题。
首先,您不能将 <select>
元素绑定到复杂对象的集合。 <select>
posts 返回其 selected 选项的值(这将是一个 int
假设 Id
属性 为 Language
是 int
).
接下来模型中的视图是 FilterViewModel
(并且您生成的表单控件具有基于这些属性的 name
属性),但是您 post 返回到不同的模型( App
) 不包含这些属性,因此无论如何都不会绑定。
您添加了一个 null
标签选项 ("Select Language"),如果它被 select 编辑,它将 post 一个 null
值,这会导致您的查询失败。
还有一些不好的做法,我在下面指出。
你的视图模型应该是
public class AppsFilterVM
{
public int? Language { get; set; }
public int? Platform { get; set; }
public IEnumerable<SelectListItem> LanguageOptions { get; set; }
public IEnumerable<SelectListItem> PlatformOptions { get; set; }
...
public IEnumerable <App> Apps { get; set; }
}
不清楚 AgeGroups
和 ProductCodes
的用途,所以我在上面的代码中省略了它们,根据您的评论,我假设用户可以通过 Language
或 Platform
或两者
控制器代码为
public ActionResult FilterApps(AppsFilterVM model)
{
var apps = _context.Apps;
if (model.Language.HasValue)
{
apps = apps.Where(x => x.LanguageId == model.Language.Value);
}
if (model.Platform.HasValue)
{
apps = apps.Where(x => x.PlatformId == model.Platform.Value);
}
model.Apps = apps;
ConfigureViewModel(model);
return View(model);
}
private void ConfigureViewModel(AppsFilterVM model)
{
// populate the selectlists
var languages = _context.Languages;
var platforms = _context.Platforms
model.LanguageOptions = new SelectList(languages, "Id", "Name");
model.PlatformOptions = new SelectList(platforms , "Id", "Name");
}
然后在视图中(注意它是 GET,而不是 POST)
@model.AppsFilterVM
....
@using (Html.BeginForm("FilterApps", "Apps", FormMethod.Get))
{
@Html.LabelFor(m => m.Language)
@Html.DropdownListFor(m => m.Language, Model.LanguageOptions, "No filter")
@Html.ValidationMessageFor(m => m.Language)
@Html.LabelFor(m => m.Platform)
@Html.DropdownListFor(m => m.Platform, Model.PlatformOptions, "No filter")
@Html.ValidationMessageFor(m => m.Platform)
<input type="submit" value="Filter" />
}
@foreach (var group in Model.AgeGroups)
{
....
还有一些您不应该做的事情。您给两个 <select>
元素相同的 id
属性,该属性无效 html(DropDownListFor()
方法已经基于 属性 生成了一个唯一的 id
姓名)。
您不应基于 <select>
的 change
事件提交表单 这不仅是意外行为,如果用户使用键盘浏览选项(例如使用箭头键, 或键入一个字符以转到以该字母开头的第一个选项,然后将立即提交表单。此外,用户可能会首先 select 从第二个下拉列表中选择一个选项,这将立即 post 在他们有机会 select 第一个选项之前。允许用户制作他们的 select 离子,检查它们,然后在他们选择时提交表格。
您的视图不应包含 linq 查询,并且您的分组和排序应在将模型传递给视图之前在控制器中完成。你的 Apps
属性 实际上应该是一个视图模型,其中包含一个 属性 作为组名,一个集合 属性 作为应用程序,(类似于你的视图模型) 这样视图就是
@foreach(var group in Model.AgeGroups)
{
@group.Name
foreach (var app in group.Apps)
{
@app.ProductCode
@app.Name
@app.Platform
}
}
您还应该考虑使用 ajax 提交您的表单,这将调用单独的服务器方法 returns 只是 Apps
的部分视图,并更新 DOM 在成功回调中,这将提高性能。例如,参考 .
总结:
我正在尝试使用两个 DropDownList 控件来筛选当前正在排序并显示在视图中的数据。
我们要学习什么 为可以使用 DropDownList
过滤数据的一对多和多对多关系创建 ViewController可能的原因 如果我的 DropdownList 代码没有严重错误,那么我用来显示数据的 ViewModel 对 DropDownList 项目没有适当的支持。
换句话说,RazorView 和我的 ViewModel 与我想要实现的目标不兼容。如果我尝试更改我的 ViewModel 或 RazorView,我会收到现有代码的无限错误循环。
或者 Linq 查询需要专家的关注
这里是FilterViewModel.cs
public IEnumerable <App> Apps { get; set; }
public IEnumerable <Language> Languages { get; set; }
public IEnumerable <Platform> Platforms { get; set; }
public IEnumerable <AgeGroup> AgeGroups { get; set; }
public IEnumerable <ProductCode> ProductCodes { get; set; }
这里是AppsController.cs
public ActionResult FilterApps(App app)
{
var apps = _context.Apps.ToList();
var languages = _context.Languages.ToList();
var productCodes = _context.ProductCodes.ToList();
var platforms = _context.Platforms.ToList();
var ageGroups = _context.AgeGroups.ToList();
var viewModel = new FilterViewModel
{
AgeGroups = ageGroups,
Languages = languages,
Platforms = platforms,
ProductCodes = productCodes,
Apps = apps
.Where(a => a.LanguageId == app.LanguageId && a.PlatformId == app.PlatformId)
// I also tried all possible combinations :(a.Lanage.Id etc)
};
return View("FilterApps", viewModel);
}
这里是FilterApps.cshtml
@model Marketing.ViewModels.FilterViewModel
<h2>FilterApps</h2>
@using (Html.BeginForm("FilterApps", "Apps", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="form-group">
@Html.DropDownListFor( m => m.Languages,
new SelectList(Model.Languages, "Id", "Name"),"Select Language",
new { @class = "form-control", @id = "dropDown" })
@Html.DropDownListFor(m => m.Platforms,
new SelectList(Model.Platforms, "Id", "Name"), "Select Platform",
new { @onchange = "this.form.submit();",
@class = "form-control", @id = "dropDown" })
</div>
}
//The existing code below is working fine so far.
@foreach (var group in Model.AgeGroups)
{
<h4>@group.Name</h4>
@foreach (var app in Model.Apps.OrderBy(a => a.AppOrder))
{
if (app.AgeGroupId == group.Id)
{
@app.ProductCode.Name
@app.Name
@app.Platform.Name
}
}
}
可能没有必要,但我希望额外的信息能有所帮助。
附加信息
App.cs 正在引用所有其他表,例如
public Language Language { get; set; }
public int LanguageId { get; set; }
public Platform Platform { get; set; }
public int PlatformId { get; set; }
and so on...
我已经尝试过的 几个断点和日志来跟踪数据,我也尝试使用以下但它破坏了我现有的排序和分组。
public App App { get; set; } //Instead of the IEnumerable<App>
您的代码存在多个问题。
首先,您不能将 <select>
元素绑定到复杂对象的集合。 <select>
posts 返回其 selected 选项的值(这将是一个 int
假设 Id
属性 为 Language
是 int
).
接下来模型中的视图是 FilterViewModel
(并且您生成的表单控件具有基于这些属性的 name
属性),但是您 post 返回到不同的模型( App
) 不包含这些属性,因此无论如何都不会绑定。
您添加了一个 null
标签选项 ("Select Language"),如果它被 select 编辑,它将 post 一个 null
值,这会导致您的查询失败。
还有一些不好的做法,我在下面指出。
你的视图模型应该是
public class AppsFilterVM
{
public int? Language { get; set; }
public int? Platform { get; set; }
public IEnumerable<SelectListItem> LanguageOptions { get; set; }
public IEnumerable<SelectListItem> PlatformOptions { get; set; }
...
public IEnumerable <App> Apps { get; set; }
}
不清楚 AgeGroups
和 ProductCodes
的用途,所以我在上面的代码中省略了它们,根据您的评论,我假设用户可以通过 Language
或 Platform
或两者
控制器代码为
public ActionResult FilterApps(AppsFilterVM model)
{
var apps = _context.Apps;
if (model.Language.HasValue)
{
apps = apps.Where(x => x.LanguageId == model.Language.Value);
}
if (model.Platform.HasValue)
{
apps = apps.Where(x => x.PlatformId == model.Platform.Value);
}
model.Apps = apps;
ConfigureViewModel(model);
return View(model);
}
private void ConfigureViewModel(AppsFilterVM model)
{
// populate the selectlists
var languages = _context.Languages;
var platforms = _context.Platforms
model.LanguageOptions = new SelectList(languages, "Id", "Name");
model.PlatformOptions = new SelectList(platforms , "Id", "Name");
}
然后在视图中(注意它是 GET,而不是 POST)
@model.AppsFilterVM
....
@using (Html.BeginForm("FilterApps", "Apps", FormMethod.Get))
{
@Html.LabelFor(m => m.Language)
@Html.DropdownListFor(m => m.Language, Model.LanguageOptions, "No filter")
@Html.ValidationMessageFor(m => m.Language)
@Html.LabelFor(m => m.Platform)
@Html.DropdownListFor(m => m.Platform, Model.PlatformOptions, "No filter")
@Html.ValidationMessageFor(m => m.Platform)
<input type="submit" value="Filter" />
}
@foreach (var group in Model.AgeGroups)
{
....
还有一些您不应该做的事情。您给两个 <select>
元素相同的 id
属性,该属性无效 html(DropDownListFor()
方法已经基于 属性 生成了一个唯一的 id
姓名)。
您不应基于 <select>
的 change
事件提交表单 这不仅是意外行为,如果用户使用键盘浏览选项(例如使用箭头键, 或键入一个字符以转到以该字母开头的第一个选项,然后将立即提交表单。此外,用户可能会首先 select 从第二个下拉列表中选择一个选项,这将立即 post 在他们有机会 select 第一个选项之前。允许用户制作他们的 select 离子,检查它们,然后在他们选择时提交表格。
您的视图不应包含 linq 查询,并且您的分组和排序应在将模型传递给视图之前在控制器中完成。你的 Apps
属性 实际上应该是一个视图模型,其中包含一个 属性 作为组名,一个集合 属性 作为应用程序,(类似于你的视图模型
@foreach(var group in Model.AgeGroups)
{
@group.Name
foreach (var app in group.Apps)
{
@app.ProductCode
@app.Name
@app.Platform
}
}
您还应该考虑使用 ajax 提交您的表单,这将调用单独的服务器方法 returns 只是 Apps
的部分视图,并更新 DOM 在成功回调中,这将提高性能。例如,参考