C# 在 ASP.NET MVC 中将多个参数传递给控制器​​;此外,在 LINQ-to-SQL 中生成即时查询

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/488061/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 05:21:17  来源:igfitidea点击:

Passing multiple parameters to controller in ASP.NET MVC; also, generating on-the-fly queries in LINQ-to-SQL

c#sqlasp.net-mvclinqcontroller

提问by Rob Burke

I'm working on a basic Issue Management System in order to learn ASP.NET MVC. I've gotten it up and running to a fairly decent level but I've run into a problem.

我正在开发一个基本的问题管理系统,以便学习 ASP.NET MVC。我已经启动并运行到相当不错的水平,但我遇到了一个问题。

I have a controller named Issue with a view called Open. /Issue/Open lists all of the open issues currently logged on the system. I've defined a route like so:

我有一个名为 Issue 的控制器,有一个名为 Open 的视图。/Issue/Open 列出当前记录在系统上的所有未解决的问题。我已经定义了这样的路线:

    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:

这工作正常(尽管我想知道是否有比 switch 更好的方法来处理我的查询定义?)但现在我希望能够在 Open Issues 视图上做两件事:

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

I can't figure out how to pass two parameters to the Controller so I can organise my queries. 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!

啊,有人能指出我正确的方向吗?干杯!

采纳答案by Craig Stuntz

  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:
  1. 从路由中删除排序。只需使用没有参数的路由。
  2. 将查询字符串参数添加到排序、过滤器等查询中。因此您的查询将如下所示:

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. Make sure and use nullable types (like string) for any of these query string parameter arguments which might not be filled in.

MVC 框架将从查询字符串参数中填充参数。确保对这些可能未填写的任何查询字符串参数参数使用可空类型(如字符串)。

I actually think this is a "more correct" way to write the URL. The URL itself identifies the resource (open issues); the query string parameters customize how to display the resource.

我实际上认为这是编写 URL 的“更正确”的方式。URL 本身标识资源(未解决的问题);查询字符串参数自定义如何显示资源。

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

回答by kimsk

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


回答by ungood

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.

这应该是对kimsk答案的评论,但出于某种原因,评论需要我接受审查,所以我必须将其发布在错误的地方。

A better way to handle an arbitrary number of query string parameters is to use an ActionFilterlike 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. This way your action is more easily tested, as it no longer depends on the Requestsingleton.

现在您可以像这样将 an 属性添加到您的操作中[QueryStringFilter("attributes")],它会将查询字符串值作为FormCollection. 这样你的动作更容易测试,因为它不再依赖于Request单例。

回答by gurra777

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