如何对 ASP.NET Core MVC 视图进行分页,以在每次用户更改页面时从控制器操作方法调用存储过程

问题描述 投票:0回答:1

我有一个 SQL Server 数据库,并使用 ASP.NET Core 8.0 MVC 应用程序和 Entity Framework Core。我想调用一个存储过程,在控制器操作中按页码和每页结果数对其结果集进行分页。

我认为视图可以使用不同的页码一遍又一遍地调用控制器操作方法,但是当视图第二次调用下一个操作时(我可以成功调用一次),模型的页码为 1 -即使我在页面上显示它并且它显示 2.

我实际上正在调用 Next、Back、First 和 Last 的操作方法,分别减少、增加或更改当前页码,然后调用搜索控制器操作方法,并为新的当前页面更新模型。我也不确定这是否是最佳实践。

我第一次调用 Next 时,页码更新为 2,存储过程再次运行并检索正确的数据。第二次调用 Next 时,当前页面作为 1 传递到模型上,即使它显示在屏幕上并显示 2。

这是适用的代码。任何帮助将不胜感激。

CREATE OR ALTER PROCEDURE [dbo].[SEARCH]      
     ...
     @PageNumber int = 1,
     @PageSize int = 20
 
    SELECT ...(columns)... 
    FROM TABLE
    WHERE
        ...
        OFFSET ((@PageNumber - 1) * @PageSize) ROWS      
        FETCH NEXT @PageSize ROWS ONLY
END

查看:

<form id="frmSearch" method="post" asp-asp-controller="Home" asp-action="Search">

... 最初调用搜索的按钮:

    <button id="submitSearch" type="submit" name="Submit" class="btn btn-lg btn-primary">Search</button>

下一个呼叫按钮:

    <input id="btnNext" type="submit" value="Next" asp-action="Next" />

控制器:

public async Task<IActionResult> Next(SearchViewModel svm)
{
    svm.CurrentPageNumber += 1;
    return await Search(svm);
}

搜索(帖子):

[HttpPost]
public async Task<IActionResult> Search(SearchViewModel svm)
{
    try
    {
        // ...
        var parameters = new[]
            {
                new SqlParameter("@PageNumber", svm.CurrentPageNumber),
                new SqlParameter("@PageSize", pagesize)
            };
 
        List<CommunicationSearchResult> communications = await _recordingContext.CommunicationSearchResults.FromSqlRaw("EXEC USP_DETAILED_SEARCH_COMMUNICATIONS @PageNumber, @PageSize", parameters).ToListAsync();

        svm.Results = communications;

        if (communications.Count > 0)
        {
            svm.TotalRecordCount = communications[0].Total;
            svm.TotalPageCount = Convert.ToInt32(Math.Ceiling((decimal)(svm.TotalRecordCount / pagesize)));
        }

        return View("Search", svm);
    }
    catch()
    { }
}
stored-procedures entity-framework-core asp.net-core-mvc razor-pages .net-8.0
1个回答
0
投票

当谈到 ASP.Net 时,一个重要的细节是,在服务器和视图之间来回传递对象的任何外观都是一种幻觉,与 MVVM /w WPF 等中的视图模型不同。为了让“模型”在传回控制器时传回除默认状态之外的任何内容,您需要在页面上有一个与该值相关的输入元素。

如果您的视图模型具有要在服务器端和/或客户端调整的 CurrentPageNumber,那么您可能会发现代码通过向页面添加该值的隐藏输入开始工作。例如:

@Html.HiddenFor(model => model.CurrentPageNumber)

当您将模型传递给视图时,您正在将该类的实例发送到 Web 服务器上的视图引擎。该视图引擎将 .cshtml 模板和模型转换为 .html 视图,以及管理表单回发等事务的 ASP.Net JavaScript。当用户发布表单或获取 FormData 以发送到服务器的 Ajax 调用时,客户端上没有“Model”实例。 JS 只是尝试解析 .html 页面上的所有输入值,以将这些值发送到服务器 POST 中。当您的控制器路由被调用时,ASP.Net 将遍历这些输入并构造一个新的 ViewModel 实例,填充传递的任何值。任何未传递的值都将保留为默认值。

拥有诸如

<p>
之类的元素内容或带有
@Model.CurrentPageNumber
的标签将在加载更新的页面时显示更新的第 2 页,但是如果没有
<input>
绑定到
@Model.CurrentPageNumber
,则更新的值将不会通过后续帖子。

分页的替代方法是在 JS 中完全在客户端跟踪当前页码,并使用 POST 有效负载传递当前页号(以及页面大小等信息),而不是在每次调用时发送视图模型。 当前页码也可以使用会话状态在服务器端进行跟踪,尽管我并不真正推荐这种存储瞬态状态的方法。 (很容易不同步,并且大量使用会话状态会占用服务器端内存)

© www.soinside.com 2019 - 2024. All rights reserved.