【问题标题】:Paginated List with Multiple Search Fields in Razor PagesRazor 页面中具有多个搜索字段的分页列表
【发布时间】:2019-10-22 19:14:25
【问题描述】:

我正在创建一个 Razor 页面应用程序,我的客户需要在其中一次搜索多个字段,但是,当我创建多个搜索字段时,搜索本身运行良好,但分页列表上的分页中断,丢失了搜索第二页上的术语并恢复为默认分页顺序。是否有我应该实现的不同列表类型,或者有没有办法有条件地优先考虑分页列表使用哪个搜索字段来维护其分页顺序并且不会丢失搜索?作为开发新手,我将在后面的代码中提供大部分代码,因为在 Razor Pages 中的分页、排序和过滤方面,我仍然不清楚这些部分是如何组合在一起的。

当我设置了允许客户端一次搜索一个字段的搜索设置时,一切都运行良好,而当我进行更改以允许多个并发搜索时,问题就出现了。

这是背后的代码:

 private readonly PFDTrustContext _context;

    public IndexModel(PFDTrustContext context)
    {
        _context = context;
    }

    public PaginatedList<Client> Clients { get; set; }

    // sorting
    public string AcctNumberSort { get; set; }
    public string FirstNameSort { get; set; }
    public string LastNameSort { get; set; }
    public string SSNSort { get; set; }
    public string CurrentSort { get; set; }

    // filtering
    public string FilterLN { get; set; }
    public string FilterFN { get; set; }
    public string FilterSSN { get; set; }
    public string FilterAcctNum { get; set; }
    public string CurrentFilter { get; set; }


    public async Task OnGetAsync(string sortOrder, string searchStringLN, string searchStringFN, string searchStringSSN, string searchStringAcctNum, string filterLN, string filterFN, string filterSSN, string filterAcctNum, string currentFilter, int? pageIndex)
    {
        CurrentSort = sortOrder;

        // Sorting
        LastNameSort = string.IsNullOrEmpty(sortOrder) ? "lastName_desc" : "";
        FirstNameSort = sortOrder == "firstName" ? "firstName_desc" : "firstName";
        AcctNumberSort = sortOrder == "acctNumber" ? "acctNumber_desc" : "acctNumber";
        SSNSort = sortOrder == "SSN" ? "SSN_desc" : "SSN";

        // Paging
        if (searchStringLN != null)
        {
            pageIndex = 1;
        }
        else
        {
            searchStringLN = filterLN;
        }

        if (searchStringFN != null)
        {
            pageIndex = 1;
        }
        else
        {
            searchStringFN = filterFN;
        }

        if (searchStringSSN != null)
        {
            pageIndex = 1;
        }
        else
        {
            searchStringSSN = filterSSN;
        }

        if (searchStringAcctNum != null)
        {
            pageIndex = 1;
        }
        else
        {
            searchStringAcctNum = filterAcctNum;
        }

        // Searching/Filtering
        FilterLN = searchStringLN;
        FilterFN = searchStringFN;
        FilterSSN = searchStringSSN;
        FilterAcctNum = searchStringAcctNum;

        if (!string.IsNullOrEmpty(FilterLN))
        {
            CurrentFilter = FilterLN;
        }
        else if (!string.IsNullOrEmpty(FilterSSN))
        {
            CurrentFilter = FilterSSN;
        }
        else if (!string.IsNullOrEmpty(FilterAcctNum))
        {
            CurrentFilter = FilterAcctNum;
        }
        else
        {
            CurrentFilter = FilterFN;
        }


        // Sorting
        IQueryable<Client> clients = from c in _context.Clients
                                     select c;

        // Searching
        if (!string.IsNullOrEmpty(searchStringLN))
        {
            clients = clients.Where(c => c.LastName.ToUpper().Contains(searchStringLN.ToUpper()));
        }
        if (!string.IsNullOrEmpty(searchStringFN))
        {
            clients = clients.Where(c => c.FirstName.ToUpper().Contains(searchStringFN.ToUpper()));
        }
        if (!string.IsNullOrEmpty(searchStringSSN))
        {
            clients = clients.Where(c => c.SSN.ToString().Contains(searchStringSSN));
        }
        if (!string.IsNullOrEmpty(searchStringAcctNum))
        {
            clients = clients.Where(c => c.AcctNumber.ToString().Contains(searchStringAcctNum));
        }

        // Sorting
        switch (sortOrder)
        {
            case "lastName_desc":
                clients = clients.OrderByDescending(c => c.LastName);
                break;
            case "acctNumber":
                clients = clients.OrderBy(c => c.AcctNumber);
                break;
            case "acctNumber_desc":
                clients = clients.OrderByDescending(c => c.AcctNumber);
                break;
            case "firstName_desc":
                clients = clients.OrderByDescending(c => c.FirstName);
                break;
            case "firstName":
                clients = clients.OrderBy(c => c.FirstName);
                break;
            case "SSN":
                clients = clients.OrderBy(c => c.SSN);
                break;
            case "SSN_desc":
                clients = clients.OrderByDescending(c => c.SSN);
                break;
            default:
                clients = clients.OrderBy(c => c.LastName);
                break;
        }

        // Pagination
        int pageSize = 12;

        Clients = await PaginatedList<Client>.CreateAsync(
            clients.AsNoTracking(), pageIndex ?? 1, pageSize);
    }

这是 Razor 页面:

 <table class="table">
     <thead>
         <tr>
             <th>
                 @Html.DisplayNameFor(model => model.Clients[0].ClientId)
             </th>
             <th>
                 <a asp-page="./Index" asp-route-sortOrder="@Model.AcctNumberSort"
               asp-route-currentFilter="@Model.FilterAcctNum">
                     @Html.DisplayNameFor(model => model.Clients[0].AcctNumber)
                 </a>
             </th>
             <th>
                 <a asp-page="./Index" asp-route-sortOrder="@Model.FirstNameSort"
               asp-route-currentFilter="@Model.FilterFN">
                     @Html.DisplayNameFor(model => model.Clients[0].FirstName)
                 </a>
             </th>
             <th>
                 <a asp-page="./Index" asp-route-sortOrder="@Model.LastNameSort"
               asp-route-currentFilter="@Model.FilterLN">
                @Html.DisplayNameFor(model => model.Clients[0].LastName)
                 </a>
             </th>
             <th>
                 @Html.DisplayNameFor(model => model.Clients[0].MdlInit)
             </th>
             <th>
                 <a asp-page="./Index" asp-route-sortOrder="@Model.SSNSort"
               asp-route-currentFilter="@Model.FilterSSN">
                     @Html.DisplayNameFor(model => model.Clients[0].SSN)
                 </a>
             </th>
             <th>
                 @Html.DisplayNameFor(model => model.Clients[0].DOB)
             </th>
             <th>
                 @Html.DisplayNameFor(model => model.Clients[0].InitialEntryDate)
             </th>
             <th></th>
         </tr>
     </thead>
     <tbody>
         @foreach (var item in Model.Clients)
         {
         <tr>
             <td>
                 @Html.DisplayFor(modelItem => item.ClientId)
             </td>
             <td>
                 @Html.DisplayFor(modelItem => item.AcctNumber)
             </td>
             <td>
                 @Html.DisplayFor(modelItem => item.FirstName)
             </td>
             <td>
                 @Html.DisplayFor(modelItem => item.LastName)
             </td>
             <td>
                 @Html.DisplayFor(modelItem => item.MdlInit)
             </td>
             <td>
                 @Html.DisplayFor(modelItem => item.SSN, "SSN")
             </td>
             <td>
                 @Html.DisplayFor(modelItem => item.DOB)
             </td>
             <td>
                 @Html.DisplayFor(modelItem => item.InitialEntryDate)
             </td>
             <td>
                 <a asp-page="./Edit" asp-route-id="@item.ClientId">Edit Client</a> |
                 <a asp-page="./Details" asp-route-id="@item.ClientId">Transactions</a>
             </td>
         </tr>
         }
     </tbody>
 </table>

 @{
     var prevDisabled = !Model.Clients.HasPreviousPage ? "disabled" : "";
     var nextDisabled = !Model.Clients.HasNextPage ? "disabled" : "";
 }


     <a asp-page="./Index"
         asp-route-SortOrder="@Model.CurrentSort"
         asp-route-pageIndex="@(Model.Clients.PageIndex - 1)"
         asp-route-currentFilter="@Model.CurrentFilter"

         class="btn btn-default @prevDisabled">
         Previous
     </a>

     <a asp-page="./Index"
         asp-route-sortOrder="@Model.CurrentSort"
         asp-route-pageIndex="@(Model.Clients.PageIndex + 1)"
         asp-route-currentFilter="@Model.CurrentFilter"

         class="btn btn-default @nextDisabled">
         Next
     </a>

最终,在浏览结果页面时,我需要分页来保留搜索词和排序顺序。如果这根本不可能,那么我想知道如何消除分页并使用其他类型的集合来达到保留同时在多个字段上搜索的能力的结果。

【问题讨论】:

    标签: c# asp.net-core pagination razor-pages


    【解决方案1】:

    创建分页链接时,您需要传递所有查询字符串参数以生成新的页面 url。

    可以通过使用asp-route-...="xxx" 对所有查询字符串值(包括搜索过滤器)进行硬编码来完成。

    另一种方法是获取当前页面查询字符串值(从'?'开始)并仅替换页码并生成新的url:

    
    <a href="@CreateUrl(Model.Clients.PageIndex - 1)">Previous</a>
    <a href="@CreateUrl(Model.Clients.PageIndex + 1)">Next</a>
    
    @{
        string CreateUrl(int index)
        {
            // Split the query string to individual parameters
            // e.g. [ "pageIndex=1", "searchString=blablabla", ...]
            var queryStringList = Request.QueryString.Value.Split('&').ToList();
    
            // Loop throw the parameters and increase the page index
            for (int i = 0; i < queryStringList.Count(); i++)
            {
                var qs = queryStringList[i];
                queryStringList[i] = qs.StartsWith("pageIndex=") ? $"pageIndex={index}" : qs;
            }
    
            // Reconstrcu the url
            return string.Join("&", queryStringList);
        }
    }
    

    或者您可以简单地使用正则表达式替换值而不拆分和重新创建 url:

    <a href="@CreateUrl(Model.Clients.PageIndex - 1)">Previous</a>
    <a href="@CreateUrl(Model.Clients.PageIndex + 1)">Next</a>
    
    @{
        string CreateUrl(int index)
        {
            var input = Request.QueryString.Value;
            var replacement = $"pageIndex={index}";
            var pattern = @"pageIndex=\d+";
            return System.Text.RegularExpressions.Regex.Replace(input, pattern, replacement);
        }
    }
    

    或者使用可以处理所有复杂分页逻辑的分页标签助手nuget,例如LazZiya.TagHelpers,从nuget安装:

    安装包 LazZiya.TagHelpers -Version 3.0.2

    为 _ViewImports 添加分页标签助手:

    @addTagHelper *, LazZiya.TagHelpers
    

    然后在需要分页控件的地方使用它:

    <paging 
        total-records="Model.TotalRecords" 
        page-no="Model.PageNo"
        query-string-key-page-no="pageIndex"
        query-string-value="@(Request.QueryString.Value)">
    </paging>
    

    tutoriallive demodocs

    【讨论】:

    • 感谢您的回复。在您上面提供的第一个示例中,您似乎将代码直接放在 Razor 页面上,我想知道,我应该在代码中的哪个位置调用方法 CreateUrl()?
    • @RavenCohoSalomé 我已更新代码以显示如何调用CreateUrl 函数
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-23
    • 2019-08-11
    • 2020-03-27
    • 2018-01-26
    • 1970-01-01
    相关资源
    最近更新 更多