如何在Asp.net MVC和实体框架中进行分页时应用过滤器?

Jay*_*len 3 c# asp.net-mvc entity-framework pagedlist asp.net-mvc-5

我有一个使用ASP.NET MVC框架编写的Web应用程序.在我,Homecontroller我有一个Index响应Get请求的动作.在此操作中,我使用IPagedList库创建页面以将记录分成多个页面.我Index@HttpGet看起来像这样

public ActionResult Index(int? id)
{
    using(var connection = new Context())
    {
        int pageNumber = (id ?? 1);
        var presenter = new Presenter
        {
            Presenter = pageNumber,
            Tasks = connection.Tasks.ToPagedList(pageNumber, 30),
            Form = new TasksFiltersViewModel()
        }

        return View(presenter);
    }
}
Run Code Online (Sandbox Code Playgroud)

我还有一个名为Index响应Post请求的动作,它会应用一些过滤器.所以在Post请求中我做了这样的事情

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Index(Presenter model)
{
    int pageNumber = (id ?? 1);
    if (ModelState.IsValid)
    {
        using(var connection = new Context())
        {
            model.Tasks = connection.Tasks
                                    .Where(task => task.Status == 5)
                                    .ToPagedList(pageNumber, 30);
        }
    }

    return View(model);
}
Run Code Online (Sandbox Code Playgroud)

这也可以正常工作,除非用户更改页面然后过滤器休息.

这是我的演示类的样子

public class Presenter
{
    public IPagedList<Task> Tasks { get; set; }
    public TasksFiltersViewModel Form { get; set; }
    public int PageNumber { get; set; }
    public IEnumerable<SelectListItem> Statuses { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

如何在保留过滤器的同时允许用户使用页面?

这是我的过滤器VM

public class TasksFiltersViewModel
{
    public int Status { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

视图看起来像这样

@using (Html.BeginForm("Index", "Tasks", FormMethod.Post, new { @class = "form-horizontal" }))
{
    @Html.AntiForgeryToken()

    <div class="form-group">
        @Html.LabelFor(m => m.Form.Status, new { @class = "control-label col-sm-3" })
        <div class="col-sm-9">
            @Html.DropDownListFor(m => m.Form.Status, Model.Statuses, new { @class = "form-control" })
            @Html.ValidationMessageFor(m => m.Form.Status, "", new { @class = "text-danger" })
        </div>

    </div>

    <div class="row">
        <div class="col-sm-9 col-md-push-3">
            <div>
                <button type="submit" class="btn btn-default">Filter</button>
            </div>
        </div>
    </div>

}

foreach (var task in Model.Tasks)
{
    <tr>
        <td>@task.Name</td>
        <td>@task.Type</td>
        <td>@Html.ActionLink("Edit", "Details", "Task", new { @id = task.Id }, new { @class = "btn btn-primary btn-sm" })</td>
    </tr>
}


@Html.PagedListPager(Model.Tasks, id => Url.Action("Index", new { id }))
Run Code Online (Sandbox Code Playgroud)

小智 5

您的表单需要回发到GET方法,该方法需要包含过滤器属性的参数.您PagedListPager在视图中的代码还需要包含这些过滤器属性,以便在导航到下一页/上一页时保留它们.请注意,Index()POST方法未使用,可以删除.

让模型包含过滤器属性的复杂对象以及绑定时的额外复杂性,因此首先将模型更改为

public class Presenter
{
    public IPagedList<Task> Tasks { get; set; }
    public int? Status { get; set; } // note nullable
    ... // add any other properties of TasksFiltersViewModel 
    public int PageNumber { get; set; }
    public IEnumerable<SelectListItem> Statuses { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后将Index()方法更改为

public ActionResult Index(int? id, int? status) // add any other parameters your filtering on
{
    int pageNumber = (id ?? 1);
    var tasks = db.Tasks; // IQueryable<Task>
    if (status.HasValue)
    {
        tasks = tasks.Where(x => x.Status == status.Value)
    }
    if (otherParametersHaveValue)
    {
        tasks = tasks.Where(....);
    }
    Presenter model = new Presenter()
    {
        PageNumber = id ?? 1,
        Status = status,
        .... // set any other filter properties from the parameters
        Statuses = new SelectList(...),
        Tasks = tasks.ToPagedList(pageNumber, 30)
    };
    return View(model );
}
Run Code Online (Sandbox Code Playgroud)

并将视图更改为

// Make the form a GET
@using (Html.BeginForm("Index", "Tasks", FormMethod.Get, new { @class = "form-horizontal" }))
{
    ....
    // Modify expression based on revised model properties
    @Html.DropDownListFor(m => m.Status, Model.Statuses, ...)
}
....
// Add filter parameters to url so they are retained
@Html.PagedListPager(Model.Tasks, id => Url.Action("Index", new { id, status = Model.Status })) // add other filter properties as required
Run Code Online (Sandbox Code Playgroud)

  • 如果你有很多过滤器属性,你可以将签名修改为`public ActionResult Index(int?id,[Bind(Prefix ="Form")] TasksFiltersViewModel filters)` - 注意`Bind`属性 - 然后在`PagedListPager` - 它需要是`new {status = Model.Form.Status}`等.请注意`TasksFiltersViewModel`中的所有属性都应该是可空的,以便更容易构建查询.然后将`Presenter`构造函数修改为`Form = filters,` (2认同)