简体   繁体   English

在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

I'm working on a basic Issue Management System in order to learn ASP.NET MVC. 我正在研究一个基本的问题管理系统,以便学习ASP.NET MVC。 I've gotten it up and running to a fairly decent level but I've run into a problem. 我已经把它运行到相当不错的水平,但我遇到了一个问题。

I have a controller named Issue with a view called Open. 我有一个名为Issue的控制器,其视图名为Open。 /Issue/Open lists all of the open issues currently logged on the system. / Issue / Open列出当前系统上记录的所有未解决问题。 I've defined a route like so: 我已经定义了这样的路线:

    routes.MapRoute( 
        "OpenSort",                                                         // Route name
        "Issue/Open/{sort}",                                                // URL with parameters
        new { controller = "Issue", action = "Open", sort = "TimeLogged" }  // Parameter defaults
    );

This is working fine so far, using the following code in IssueController.cs: 到目前为止,这是正常工作,使用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());
}

This is working fine (although, I wonder if there is a better way to handle my definition of the query than a switch?) but now I want to be able to do two things on the Open Issues view: 这工作正常(虽然,我想知道是否有更好的方法来处理我的查询定义而不是交换机?)但现在我希望能够在Open Issues视图上做两件事:

  1. Sort by any of the headings - OK 按任何标题排序 - 好的
  2. Filter on certain headings (Technician, Customer, Category, Priority, Status) - ?? 过滤某些标题(技术人员,客户,类别,优先级,状态) - ??

I can't figure out how to pass two parameters to the Controller so I can organise my queries. 我无法弄清楚如何将两个参数传递给Controller,以便我可以组织我的查询。 I've also just realised that unless I figure out how to generate my queries on the fly I am going to need (number of sort options) * (number of filter options) in my switch. 我也刚刚意识到,除非我弄清楚如何动态生成我的查询,我将需要(排序选项的数量)*(过滤器选项的数量)在我的交换机中。

Argh, can anyone point me in the right direction? 唉,有人能指出我正确的方向吗? Cheers! 干杯!

  1. Remove sort from the route. 从路线中删除排序。 Just use a route without a parameter. 只需使用没有参数的路线。
  2. Add query string parameters to the query for the sort, filter, etc. So your query will look like: 将查询字符串参数添加到查询中以进行排序,过滤等。因此,您的查询将如下所示:

http://example.com/Issue/Open?sort=ID&filter=foo http://example.com/Issue/Open?sort=ID&filter=foo

public ActionResult Open(string sort, string filter)

The MVC framework will fill in the arguments from the query string parameters. MVC框架将填充查询字符串参数的参数。 Make sure and use nullable types (like string) for any of these query string parameter arguments which might not be filled in. 确保并为可能未填写的任何查询字符串参数参数使用可空类型(如字符串)。

I actually think this is a "more correct" way to write the URL. 我实际上认为这是一种“更正确”的方式来编写URL。 The URL itself identifies the resource (open issues); URL本身标识资源(开放问题); the query string parameters customize how to display the resource. 查询字符串参数自定义如何显示资源。

As far as the number of queries go, remember that you do not have to build the entire query at once. 就查询数量而言,请记住您不必一次构建整个查询。 You can use the .OrderBy extension method to re-order an existing IQueryable<T>, and similarly with .Where. 您可以使用.OrderBy扩展方法重新排序现有的IQueryable <T>,类似于.Where。

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);
}     

If you expect arbitary number of parameters, you could do something like this. 如果你期望任意数量的参数,你可以做这样的事情。


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"];
   ...


This should be a comment to kimsks answer, but for some reason commenting requires me to be vetted, so I have to post it in the wrong place. 这应该是对kimsks答案的评论,但由于某些原因,评论要求我进行审查,所以我必须将其发布在错误的地方。

A better way to handle an arbitrary number of query string parameters is to use an ActionFilter like so: 处理任意数量的查询字符串参数的更好方法是使用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);
    }
}

Now you can add the an attribute to your action like so [QueryStringFilter("attributes")] and it will pass in the query string values as a FormCollection . 现在,您可以将an属性添加到您的操作中,如[QueryStringFilter("attributes")] ,它将作为FormCollection传递查询字符串值。 This way your action is more easily tested, as it no longer depends on the Request singleton. 这样您的操作就更容易测试,因为它不再依赖于Request单例。

Instead of the switch, you could use Dynamic Linq which lets you say: 您可以使用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 http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM