代码之家  ›  专栏  ›  技术社区  ›  James Alexander

搜索表单的ASP.NET MVC分页

  •  4
  • James Alexander  · 技术社区  · 14 年前

    我在MVC中读过几篇关于分页的文章,但是没有一篇文章描述了一个场景,在这个场景中,我有一个类似搜索表单的东西,一旦用户单击提交,我就想在表单下面显示搜索条件(带分页)的结果。

    我的问题是,我使用的分页解决方案将创建<a href=“…”>链接,这些链接将像这样传递所需的页面: http://mysite.com/search/2/ 虽然这一切都很好,但我没有将查询结果发送到内存中的数据库或其他任何东西,所以我需要再次查询数据库。

    如果结果是由post controller操作for/search处理的,并且数据的第一页也是这样呈现的,那么当用户单击移动到第2页时,如何获得相同的结果(基于用户指定的表单条件)?

    一些javascript巫术?利用会话状态?使我的get controller操作具有搜索条件预期的相同变量(但可选),调用get操作时,实例化一个formcollection实例,填充它并将其传递给post-action方法(在那里满足dry)?

    有人能为这个场景指出正确的方向吗,或者提供过去已经实现的示例?谢谢!

    6 回复  |  直到 13 年前
        1
  •  0
  •   Charlino    14 年前

    我的方法是让一个操作同时处理POST和GET场景。

    这是我的,可以通过get和post方法处理:

    public ViewResult Index([DefaultValue(1)] int page,
                            [DefaultValue(30)] int pageSize,
                            string search,
                            [DefaultValue(0)] int regionId,
                            [DefaultValue(0)] int eventTypeId,
                            DateTime? from,
                            DateTime? to)
    {
        var events = EventRepo.GetFilteredEvents(page, pageSize, search, regionId, eventTypeId, from, to);
        var eventFilterForm = EventService.GetEventFilterForm(from, to);
    
        var eventIndexModel = new EventIndexModel(events, eventFilterForm);
    
        return View("Index", eventIndexModel);
    }
    

    这个 eventFilterForm 是一个包含 IEnumerable<SelectListItem> 搜索表单的属性。

    这个 eventIndexModel 是一个结合了 事件过滤器 以及搜索结果- events

    这个 事件 是一种特殊类型的 IPagedList . 你可以得到更多的信息和代码 here here .第一个链接讨论ipagedlist,第二个链接具有您应该需要的高级分页场景。

    高级分页使用以下方法:

    public static string Pager(this HtmlHelper htmlHelper, int pageSize, int currentPage, int totalItemCount, RouteValueDictionary valuesDictionary)
    

    我是这样使用的:

    <%= Html.Pager(Model.Events.PageSize,
                   Model.Events.PageNumber,
                   Model.Events.TotalItemCount,
                   new
                   {
                       action = "index",
                       controller = "search",
                       search = ViewData.EvalWithModelState("Search"),
                       regionId = ViewData.EvalWithModelState("RegionId"),
                       eventTypeId = ViewData.EvalWithModelState("EventTypeId"),
                       from = ViewData.EvalDateWithModelState("From"),
                       to = ViewData.EvalDateWithModelState("To")
                   }) %>
    

    这将创建如下所示的链接:

    事件/搜索?regionid=4&eventtypeid=39&from=2009/09/01&to=2010/08/31&page=3

    HTHs
    查尔斯

    PS。 EvalWithModelState 如下:

    PPS。如果你想在get变量中输入日期-我建议你阅读 my blog post 关于它…-)

    /// <summary>
    /// Will get the specified key from ViewData. It will first look in ModelState
    /// and if it's not found in there, it'll call ViewData.Eval(string key)
    /// </summary>
    /// <param name="viewData">ViewDataDictionary object</param>
    /// <param name="key">Key to search the dictionary</param>
    /// <returns>Value in ModelState if it finds one or calls ViewData.Eval()</returns>
    public static string EvalWithModelState(this ViewDataDictionary viewData, string key)
    {
        if (viewData.ModelState.ContainsKey(key))
            return viewData.ModelState[key].Value.AttemptedValue;
    
        return (viewData.Eval(key) != null) ? viewData.Eval(key).ToString() : string.Empty;
    }
    
        2
  •  0
  •   Martin    14 年前

    使搜索参数成为视图模型的一部分:

    public SearchViewModel
    {
        string SearchParameters { get; set; }
        List<SearchObjects> SearchResults { get;set; }
    }
    

    然后只需将搜索文本框设置为搜索参数。

    除非返回所有结果,然后以某种方式将这些结果存储在页面中,否则无法“存储”搜索查询。这效率太低了。Web是无状态的,因此您必须返回数据库并重新查询更多结果。

        3
  •  0
  •   Brian Mains    14 年前

    我明白你在说什么;你可以把表单改成使用按钮,每次都把页面贴回去。或者,您可以将URL中用于分页的所有条件作为查询字符串变量传递。或者,您可以使用jquery进行发布(它有一个可以从链接单击或其他单击调用的$.Post方法)( http://api.jquery.com/jQuery.post/ )

    Hth.

        4
  •  0
  •   Mike Powell    14 年前

    如果在查询字符串中包含搜索文本以及当前结果页,而不是发布搜索文本,则此问题将消失。作为一个额外的好处,你的用户可以将他们的搜索结果加上书签。

    为此,搜索按钮只需使用搜索框的当前值构建获取请求URL。这可以在javascript中完成,也可以使用get作为搜索表单的方法属性,例如 <form method="get" action="/search"> .

        5
  •  0
  •   Community Paul Sweatte    7 年前

    我建议缓存您的搜索结果并给它们一个ID。然后对于每个分页链接,您可以将搜索ID作为参数(在每个搜索页面链接上)引用,在您的操作中,将其从缓存中提取,然后对其进行查询。

    使用这个方法,你不需要担心除第一个以外的任何事情 POST 提交搜索表单。

    Refer to my post 了解更多详细信息。

        6
  •  0
  •   Sean Chase    13 年前

    我也有同样的问题 here's what I did .

    1. 从nuget下载pagedlist
    2. 更改窗体以执行get并创建类似于此的ViewModel类型(如果您像我一样喜欢冒险作品和模型绑定):

    `

    using PagedList;
    namespace SearchFormResultPagingExample.Models {
    
      public class SearchViewModel {
        public int? Page { get; set; }
        public string EmailAddress { get; set; }
        public string LastName { get; set; }
        public IPagedList<Contact> SearchResults { get; set; }
        public string SearchButton { get; set; }
      }
    }
    

    `

    3.使用viewModel作为控制器操作方法的参数

    using System.Linq;
    using System.Web.Mvc;
    using SearchFormResultPagingExample.Models;
    using PagedList; //NOTE: use Nuget to reference PagedList
    
    namespace SearchFormResultPagingExample.Controllers {
        public class SearchController : Controller {
            const int RecordsPerPage = 25;
    
            public ActionResult Index(SearchViewModel model) {
                if (!string.IsNullOrEmpty(model.SearchButton) || model.Page.HasValue) {
                    var entities = new AdventureWorksEntities();
                    var results = entities.Contacts.Where(c => c.LastName.StartsWith(model.LastName) && c.EmailAddress.StartsWith(model.EmailAddress))
                        .OrderBy(o => o.LastName);
    
                    var pageIndex = model.Page ?? 0;
                    model.SearchResults = results.ToPagedList(pageIndex, 25);
                }
                return View(model);
            }
        }
    }
    

    在视图中使用寻呼机:

    @model SearchFormResultPagingExample.Models.SearchViewModel
    @using PagedList.Mvc;
    
    <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
    <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
    
    @using (Html.BeginForm("Index", "Search", FormMethod.Get)) {
        @Html.ValidationSummary(false)
        <fieldset>
            <legend>Contact Search</legend>
    
            <div class="editor-label">
                @Html.LabelFor(model => model.EmailAddress)
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => model.EmailAddress)
                @Html.ValidationMessageFor(model => model.EmailAddress)
            </div>
    
            <div class="editor-label">
                @Html.LabelFor(model => model.LastName)
            </div>
            <div class="editor-field">
                @Html.EditorFor(model => model.LastName)
                @Html.ValidationMessageFor(model => model.LastName)
            </div>
    
            <p>
                <input name="SearchButton" type="submit" value="Search" />
            </p>
        </fieldset>
    }
    
    @if (Model.SearchResults != null && Model.SearchResults.Count > 0) {
        foreach (var result in Model.SearchResults) {
                <hr />
                <table width="100%">
                    <tr>
                        <td valign="top" width="*">
                            <div style="font-weight: bold; font-size:large;">@result.LastName, @result.FirstName</div>
                            @result.Title<br />
                            @result.Phone<br />
                            @result.EmailAddress
                        </td>
                    </tr>
                </table>
        }
            <hr />
    
            @Html.PagedListPager(Model.SearchResults,
                page => Url.Action("Index", new RouteValueDictionary() {
                   { "Page", page }, 
                   { "EmailAddress", Model.EmailAddress },
                   { "LastName", Model.LastName }
                }),
                PagedListRenderOptions.PageNumbersOnly)
    }
    

    MVC将强制查询字符串进出您的viewModel类型参数。它很光滑!