在 ASP.NET MVC 中向控制器传递多个参数;此外,在 LINQ-to-SQL 中生成动态查询
Posted
技术标签:
【中文标题】在 ASP.NET MVC 中向控制器传递多个参数;此外,在 LINQ-to-SQL 中生成动态查询【英文标题】:Passing multiple parameters to controller in ASP.NET MVC; also, generating on-the-fly queries in LINQ-to-SQL 【发布时间】:2009-01-28 15:34:50 【问题描述】:我正在开发一个基本的问题管理系统以学习 ASP.NET MVC。我已经将它启动并运行到相当不错的水平,但我遇到了问题。
我有一个名为 Issue 的控制器和一个名为 Open 的视图。 /Issue/Open 列出了当前记录在系统上的所有未解决的问题。我已经定义了这样的路线:
routes.MapRoute(
"OpenSort", // Route name
"Issue/Open/sort", // URL with parameters
new controller = "Issue", action = "Open", sort = "TimeLogged" // Parameter defaults
);
到目前为止,这工作正常,在 IssueController.cs 中使用以下代码:
public ActionResult Open(string sort)
var Issues = from i in db.Issues where i.Status == "Open" orderby i.TimeLogged ascending select i;
switch (sort)
case "ID":
Issues = from i in db.Issues where i.Status == "Open" orderby i.ID ascending select i;
break;
case "TimeLogged":
goto default;
case "Technician":
Issues = from i in db.Issues where i.Status == "Open" orderby i.Technician ascending select i;
break;
case "Customer":
Issues = from i in db.Issues where i.Status == "Open" orderby i.Customer ascending select i;
break;
case "Category":
Issues = from i in db.Issues where i.Status == "Open" orderby i.Category ascending select i;
break;
case "Priority":
Issues = from i in db.Issues where i.Status == "Open" orderby i.Priority ascending select i;
break;
case "Status":
Issues = from i in db.Issues where i.Status == "Open" orderby i.Status ascending select i;
break;
default:
break;
ViewData["Title"] = "Open Issues";
ViewData["SortID"] = sort.ToString();
return View(Issues.ToList());
这很好用(虽然,我想知道是否有比开关更好的方法来处理我的查询定义?)但现在我希望能够在 Open Issues 视图中做两件事:
-
按任何标题排序 - 确定
过滤某些标题(技术人员、客户、类别、优先级、状态) - ??
我不知道如何将两个参数传递给控制器,以便组织查询。我也刚刚意识到,除非我弄清楚如何动态生成我的查询,否则我的开关中将需要(排序选项的数量)*(过滤选项的数量)。
啊,谁能指出我正确的方向?干杯!
【问题讨论】:
【参考方案1】:-
从路径中删除排序。只需使用不带参数的路由即可。
将查询字符串参数添加到用于排序、过滤等的查询中。这样您的查询将如下所示:
http://example.com/Issue/Open?sort=ID&filter=foo
public ActionResult Open(string sort, string filter)
MVC 框架将从查询字符串参数中填充参数。确保对这些可能未填写的查询字符串参数参数中的任何一个使用可空类型(如字符串)。
我实际上认为这是编写 URL 的“更正确”的方式。 URL 本身标识资源(未解决的问题);查询字符串参数自定义如何显示资源。
就查询数量而言,请记住您不必一次构建整个查询。您可以使用 .OrderBy 扩展方法对现有的 IQueryable
var Issues = from i in db.Issues where i.Status == "Open" select i;
switch (sort)
case "ID":
Issues = Issues.OrderBy(i => i.ID);
break;
// [...]
default:
Issues = Issues.OrderBy(i => i.TimeLogged);
【讨论】:
+1 - 路由不应包含排序和过滤之类的 UI 糖果,因为它会使路由变得混乱,并且很难在不使路由的目的不明确的情况下表达排序和过滤之类的内容。 另外,如果排序字符串总是要匹配属性名称,我认为你应该能够使用反射,获取属性,并在运行时构建表达式......但我没有线索如何做到这一点! Huey,最简单的方法是使用 Microsoft Dynamic LINQ (Google it)。 提示:避免使用 'id' 作为参数名 感谢 Craig,您的回答对我的项目有帮助。【参考方案2】:如果您期望任意数量的参数,您可以这样做。
public ActionResult Open()
string[] keys = Request.QueryString.AllKeys;
Dictionary queryParams = new Dictionary();
foreach (string key in keys)
queryParams[key] = Request.QueryString[key];
string sort = queryParams["sort"];
...
【讨论】:
【参考方案3】:这应该是对kimsks回答的评论,但由于某种原因,评论需要我经过审查,所以我必须将其发布在错误的地方。
处理任意数量的查询字符串参数的更好方法是使用ActionFilter
,如下所示:
public class QueryStringFilterAttribute : ActionFilterAttribute
public string ParameterName get; private set;
public QueryStringFilterAttribute(string parameterName)
if(string.IsNullOrEmpty(parameterName))
throw new ArgumentException("ParameterName is required.");
ParameterName = parameterName;
public override void OnActionExecuting(ActionExecutingContext filterContext)
var qs = new FormCollection(filterContext.HttpContext.Request.QueryString);
filterContext.ActionParameters[ParameterName] = qs;
base.OnActionExecuting(filterContext);
现在您可以像[QueryStringFilter("attributes")]
那样将an 属性添加到您的操作中,它将以FormCollection
的形式传入查询字符串值。这样,您的操作就更容易测试,因为它不再依赖于 Request
单例。
【讨论】:
【参考方案4】:您可以使用 Dynamic Linq 而不是开关,它可以让您说:
Issues = Issues.OrderBy("Status");
http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
【讨论】:
【参考方案5】:请查看下面描述所有过程的帖子 http://www.c-sharpcorner.com/UploadFile/4b0136/editing-multiple-records-using-model-binding-in-mvc/
【讨论】:
以上是关于在 ASP.NET MVC 中向控制器传递多个参数;此外,在 LINQ-to-SQL 中生成动态查询的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET MVC 传递多个可选参数 field=value