在ASP.NET MVC5中實現具有服務器端過濾、排序和分頁的GridView

背景

在前一篇文章《【初學者指南】在ASP.NET MVC 5中創建GridView》中,我們學習瞭如何在 ASP.NET MVC 中實現 GridView,類似於 ASP.NET web 表單的功能。通過前文,我們已經瞭解到使用 jQuery 插件的數據表可以很容易地實現具有搜索、排序和分頁等重要功能的表格。

前文中需要注意的是,所有通過插件實現的特性都是客戶端的,這意味着所有的數據都首先在頁面載入,然後由插件來處理客戶端搜索、分頁和排序的數據。如果數據表不是特別大,這麼做是可以的;但是,如果數據表很大或者數據會隨着應用的使用而不斷增加,就會引起問題。如果這樣的問題確實發生了,從長遠來講,這種創建表格方式將不是一個好選擇。

介紹

在本文中,我們將會學習如何實現服務器端的分頁,搜索和排序功能。從長遠來講,這是一種更好的方式來應對數據集特別大的情況。

我們將會修改前文中的源代碼,現在就開始吧!

Datatables.MVC5

首先,我們需要從 NuGet 包管理器中安裝 datatables.mvc5。這是 Stefan Nuxoll 實現的綁定在控制器上的數據集模型。我們爲什麼需要這個包?這是由於綁定將會提供一個附着在控制器上的強類型的模型,這將有助於我們避免讀取請求參數,也會將我們從請求的參數類型轉換中解救出來。請求對象中的所有參數傳遞都不是安全類型的,所以我們必須手動的將它們轉換到目的類型,這也將有助於開發人員專注於業務邏輯,而不用總是考慮 HTTP 參數,檢查參數、轉化參數。

綁定的好處之一是:如果業務需要,可以在請求中發送一個自定義參數。

你可以通過提供 IDataTablesRequest 來實現添加自定義的參數,你也需要重寫它的 BindModel 和 MapAdditionalColumns 方法。

數據庫創建

現在讓我們創建文章中會用到的數據庫和表,打開 SQL Management Studio 並運行以下腳本:

CREATE DATABASE [GridExampleMVC] 
 GO 
 CREATE TABLE [dbo].[Assets] ( 
     [AssetID]                   UNIQUEIDENTIFIER NOT NULL, 
     [Barcode]                   NVARCHAR (MAX)   NULL, 
     [SerialNumber]              NVARCHAR (MAX)   NULL, 
     [FacilitySite]              NVARCHAR (MAX)   NULL, 
     [PMGuide]                   NVARCHAR (MAX)   NULL, 
     [AstID]                     NVARCHAR (MAX)   NOT NULL, 
     [ChildAsset]                NVARCHAR (MAX)   NULL, 
     [GeneralAssetDescription]   NVARCHAR (MAX)   NULL, 
     [SecondaryAssetDescription] NVARCHAR (MAX)   NULL, 
     [Quantity]                  INT              NOT NULL, 
     [Manufacturer]              NVARCHAR (MAX)   NULL, 
     [ModelNumber]               NVARCHAR (MAX)   NULL, 
     [Building]                  NVARCHAR (MAX)   NULL, 
     [Floor]                     NVARCHAR (MAX)   NULL, 
     [Corridor]                  NVARCHAR (MAX)   NULL, 
     [RoomNo]                    NVARCHAR (MAX)   NULL, 
     [MERNo]                     NVARCHAR (MAX)   NULL, 
     [EquipSystem]               NVARCHAR (MAX)   NULL, 
     [Comments]                  NVARCHAR (MAX)   NULL, 
     [Issued]                    BIT              NOT NULL, 
     CONSTRAINT [PK_dbo.Assets] PRIMARY KEY CLUSTERED ([AssetID] ASC)  
 ) 
 GO

這是附屬在源代碼上的一個完整的 SQL 腳本文件,可以用它使用簡單的數據來創建數據庫和表。

設置項目

現在,創建一個新的 ASP.NET MVC 5 Web 應用程序。打開 Visual Studio 2015,點擊文件>>新建>>項目。

從該對話框中,跳轉到 Web,並選擇 ASP.NET Web 應用程序項目,然後單擊確定。

在模板頁面,選擇 MVC,如果編寫了單元測試,請先做檢查,然後點擊確定。

我們的工程都是用基本的功能創建的。現在,我們開始創建數據庫上下文類,這個類將會被Data Access實體框架使用。

創建模型和數據訪問

首先,我們需要爲 Asset 表創建一個模型,我們將會使用這個模型通過 ORM 來恢復數據。

在模型文件夾中,創建一個名爲 Asset 的新類:

using System.ComponentModel.DataAnnotations;
namespace GridExampleMVC.Models
{
    public class Asset
    {
        public System.Guid AssetID { get; set; }
        [Display(Name = "Barcode")]
        public string Barcode { get; set; }
        [Display(Name = "Serial-Number")]
        public string SerialNumber { get; set; }
        [Display(Name = "Facility-Site")]
        public string FacilitySite { get; set; }
        [Display(Name = "PM-Guide-ID")]
        public string PMGuide { get; set; }
        [Required]
        [Display(Name = "Asset-ID")]
        public string AstID { get; set; }
        [Display(Name = "Child-Asset")]
        public string ChildAsset { get; set; }
        [Display(Name = "General-Asset-Description")]
        public string GeneralAssetDescription { get; set; }
        [Display(Name = "Secondary-Asset-Description")]
        public string SecondaryAssetDescription { get; set; }
        public int Quantity { get; set; }
        [Display(Name = "Manufacturer")]
        public string Manufacturer { get; set; }
        [Display(Name = "Model-Number")
        public string ModelNumber { get; set; }
        [Display(Name = "Main-Location (Building)")]
        public string Building { get; set; }
        [Display(Name = "Sub-Location 1 (Floor)")]
        public string Floor { get; set; }
        [Display(Name = "Sub-Location 2 (Corridor)")]
        public string Corridor { get; set; }
        [Display(Name = "Sub-Location 3 (Room No)")]
        public string RoomNo { get; set; }
        [Display(Name = "Sub-Location 4 (MER#)")]
        public string MERNo { get; set; }
        [Display(Name = "Sub-Location 5 (Equip/System)")]
        public string EquipSystem { get; set; }
        public string Comments { get; set; }
        public bool Issued { get; set; }
    }
}

現在從解決方案資源管理器跳轉到模型文件夾,並打開 IdentityModels.cs 文件。我們將在數據庫上下文中爲 Asset 表添加一個屬性,這個屬性將會成爲 Asset 表的實體框架代表,用來創建腳本。在 ApplicationDbContext 類中添加新的屬性:

public class ApplicationDbContext : IdentityDbContext<applicationuser>
{
    public ApplicationDbContext(): base("DefaultConnection", throwIfV1Schema: false)
    {

    }
    public DbSet<asset> Assets { get; set; }
    public static ApplicationDbContext Create()
    {
        return new ApplicationDbContext();
    }
}

以上是 ASP.NET identity 2.0 的默認實體框架設置,我們通過爲 Asset 表添加新的 DbSet 來擴展它。

現在,在控制器文件夾中添加一個空的名爲 AssetController 的控制器,這個控制器件將用於所有 Asset 的相關工作。

public class AssetController : Controller
    {
        // GET: Asset
        public ActionResult Index()
        {
            return View();
        }

jQuery 數據表的安裝

現在我們需要安裝用於創建表格的 JQuery DataTables,進入Tools >> NuGet Package Manager >> Manage Nuget Packages for Solution,並點擊它。

安裝包管理器默認是打開的,它會在你的解決方案中顯示成已安裝的 nugget 包,點擊瀏覽按鈕,然後搜索 JQuery DataTables 包,選擇它並檢查已安裝了 JQuery DataTables 的項目解決方案。在我們的案例裏,我們將會以每一個需求的方式將其安裝在 GridExampleMVC web 中,然後點擊安裝按鈕。

Visual Studio 將會提示是否要修改解決方案,你需要點擊 Ok 來繼續安裝 JQuery DataTables 包。

在 nugget 包安裝成功後,我們需要在視圖中引入 jQuery DataTables 的必要的 JS 和 CSS,爲此,我們需要註冊 jQuery DataTables,請打開位於 App_Start 文件夾中的 BundleConfig.cs 文件並在 CSS 和 JS 文件的結尾處添加以下代碼:

bundles.Add(new ScriptBundle("~/bundles/datatables").Include(
                        "~/Scripts/DataTables/jquery.dataTables.min.js",
                        "~/Scripts/DataTables/dataTables.bootstrap.js"));

bundles.Add(new StyleBundle("~/Content/datatables").Include(
          "~/Content/DataTables/css/dataTables.bootstrap.css"));

在爲數據表添加了腳本和 CSS 之後,我們需要在總體佈局中添加它們,默認情況下, _Layout.cshtml 位於 Views >> Shared 中,_ViewStart.cshtml 也默認位於這裏。

安裝 Datatables.net 包

現在我們開始安裝 datatables.mvc5,點擊 Tools >> NuGet Package Manager >> Manage Nuget Packages for Solution,並點擊它。

安裝包管理器默認是打開的,它會在你的解決方案中顯示成已安裝的 nugget 包,點擊瀏覽按鈕,然後搜索 DataTables.mvc5,選擇它並檢查想要安裝這個包的項目解決方案。這個時候,我們開始在 GridExampleMVC Web 工程中安裝 DataTables.mvc5,點進安裝按鈕。

請在搜索結果中選擇正確的包並安裝它。

如果完成了包的安裝,你將會在工程中看到以下引用界面:

配置數據庫的連接字符串

在寫控制器代碼之前,我們需要爲實體框架配置連接字符串,以便在操作數據庫時來連接數據庫。因此,我們的連接字符串應該被指定給一個有效的數據源,以便我們在運行時應用不會被打斷。

爲了做到這一點,請打開 web.config 併爲數據庫提供連接字符串。在配置文件中,你會發現下面配置節點中的連接字符串,你需要在節點中根據你的系統來修改連接字符串。

<connectionstrings>
    <add connectionstring="Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=GridExampleMVC;
     Integrated Security=True;MultipleActiveResultSets=true" name="DefaultConnection"
     providername="System.Data.SqlClient"/>
</connectionstrings>

現在,請在控制器中添加數據庫上下文的屬性,以便我們恩給你夠在數據庫中執行請求。

private ApplicationDbContext _dbContext;
public ApplicationDbContext DbContext
{
    get
    {
        return _dbContext ?? HttpContext.GetOwinContext().Get<applicationdbcontext>();
    }
    private set
    {
        _dbContext = value;
    }
}

我們將會在任何需要的控制器行爲中,使用這個屬性查詢數據庫。

進入 Index.cshtml 文件並通過移除表單的 thead 和 tbody 元素來更新 HTML,更新 HTML 如下所示:

<div class="row">
    <div class="col-md-12">
        <div class="panel panel-primary list-panel" id="list-panel">
            <div class="panel-heading list-panel-heading">
                <h1 class="panel-title list-panel-title">Assets</h1>
            </div>
            <div class="panel-body">
                <table id="assets-data-table" class="table table-striped table-bordered"
                 style="width:100%;">
                </table>
            </div>
        </div>
    </div>
</div>

jQuery 數據表初始化

我們刪除了表單的 head 和 body 元素,因爲這些會通過數據表插件自身生成。現在我們必須升級 jQuery 數據表初始化,以便它能夠用過服務器端的 ajaxing 來加載數據。

爲此,在 Index.cshtml 視圖中添加一下代碼:

@section Scripts
{   
<script type="text/javascript">
        var assetListVM;
        $(function () {
            assetListVM = {
                dt: null,
                init: function () {
                    dt = $('#assets-data-table').DataTable({
                        "serverSide": true,
                        "processing": true,
                        "ajax": {
                            "url": "@Url.Action("Get","Asset")"
                        },
                        "columns": [
                            { "title": "Bar Code", "data": "BarCode", "searchable": true },
                            { "title": "Manufacturer", "data": "Manufacturer", "searchable": true },
                            { "title": "Model", "data": "ModelNumber", "searchable": true },
                            { "title": "Building", "data": "Building", "searchable": true },
                            { "title": "Room No", "data": "RoomNo" },
                            { "title": "Quantity", "data": "Quantity" }
                        ],
                        "lengthMenu": [[10, 25, 50, 100], [10, 25, 50, 100]],
                    });
                }
            }
            // initialize the datatables
            assetListVM.init();
        });
</script>

我們已經在 init 函數中編寫了數據表初始化代碼,在 init 函數中,我們設置 serverSide 屬性爲 true,這也就告訴表格會在服務器端進行分頁,過濾和排序,現在所有的數據不會立刻加載,而是第一頁數據會默認展示出來,更多的數據會當用戶觸發時才加載,處理的屬性會在檢索行爲中顯示這個加載過程。如果不想在數據加載時,顯示這樣的消息,可以將它默認狀態設爲 false,接下來,我們定義數據表的回調行爲,在我們通過行屬性指定了需要展示的行之後,lengthMenu 則會用於顯示每頁數據的數目。當寫入 document.ready 文件時,assetListVM.init( ) 函數將會被調用。

安裝 System.Linq.Dynamic 包

接着,我們將在 AssetController 中編寫 Get 行爲的代碼。首先我們需要引用 System.Linq.Dynamic,以便在行爲中可以使用動態鏈接方法。再一次進入 NuGet 包管理器搜索 System.Linq.Dynamic,並在項目中安裝它。

實現控制器中的排序、篩選和分頁

在完成安裝之後,進入 AssetController,編寫 Get 行爲的實現代碼:

public ActionResult Get([ModelBinder(typeof(DataTablesBinder))] IDataTablesRequest requestModel)
{
    IQueryable<asset> query = DbContext.Assets;
    var totalCount = query.Count();
 
    #region Filtering
    // Apply filters for searching
    if (requestModel.Search.Value != string.Empty)
    {
        var value = requestModel.Search.Value.Trim();
        query = query.Where(p => p.Barcode.Contains(value) ||
                                 p.Manufacturer.Contains(value) ||
                                 p.ModelNumber.Contains(value) ||
                                 p.Building.Contains(value)
                           );
     }
     var filteredCount = query.Count();
     #endregion Filtering
     #region Sorting
     // Sorting
     var sortedColumns = requestModel.Columns.GetSortedColumns();
     var orderByString = String.Empty;
     foreach (var column in sortedColumns)
     {
        orderByString += orderByString != String.Empty ? "," : "";
        orderByString += (column.Data) +
          (column.SortDirection == Column.OrderDirection.Ascendant ? " asc" : " desc");
     }
     query = query.OrderBy(orderByString == string.Empty ? "BarCode asc" : orderByString);
     #endregion Sorting
     // Paging
     query = query.Skip(requestModel.Start).Take(requestModel.Length);
     var data = query.Select(asset => new
     {
        AssetID = asset.AssetID,
        BarCode = asset.Barcode,
        Manufacturer = asset.Manufacturer,
        ModelNumber = asset.ModelNumber,
        Building = asset.Building,
        RoomNo = asset.RoomNo,
        Quantity = asset.Quantity
     }).ToList();
     return Json(new DataTablesResponse(requestModel.Draw, data, filteredCount, totalCount),
                 JsonRequestBehavior.AllowGet);
}

我們正在使用實體框架來訪問數據,但它不是強制性的,你也可以通過 ADO.Net 來實現,唯一需要做的,就是從 DataTableResponse 實例行爲中返回 JSON  , 如果在腳本中正確定義了行,數據表就會正確的顯示數據。

我們正在獲取 Assets 的引用,以便能夠鏈接到實體框架請求數據,我們可以通過 Count()函數來獲取數據集表的數據數目,這個數據將會傳遞到 DataTablesResponse 構造函數中,成爲行爲方法的最後一行。

IQueryable<asset> query = DbContext.Assets;
var totalCount = query.Count();

在這之後,我們就有了通過用戶定義的標準來過濾數據的過濾邏輯了,以下的代碼具有自注釋:

if (requestModel.Search.Value != string.Empty)
{
   var value = requestModel.Search.Value.Trim();
   query = query.Where(p => p.Barcode.Contains(value) ||
                            p.Manufacturer.Contains(value) ||
                            p.ModelNumber.Contains(value) ||
                            p.Building.Contains(value) );
}

所以,我們需要做的就是檢查用戶是否在文本框中設定了搜索標準,然後檢查所有列中是否符合標準的數據都返回了。

在這之後,我們就實現了排序邏輯,排序列的信息附帶在使用自定義模型綁定的模型中,使用 System.Linq.Dynamic 我們能夠避免 if 和 switch 語句,我們將列迭代在用戶請求的排序上,並且通過以下代碼排列行:

var sortedColumns = requestModel.Columns.GetSortedColumns();
    var orderByString = String.Empty;
    foreach (var column in sortedColumns)
    {
       orderByString += orderByString != String.Empty ? "," : "";
       orderByString += (column.Data) +
         (column.SortDirection == Column.OrderDirection.Ascendant ? " asc" : " desc");
    }
    query = query.OrderBy(orderByString == string.Empty ? "BarCode asc" : orderByString);

最後,我們應用分頁部分的功能,並檢查用戶選擇的頁面,默認會加載第一頁,在這之後,我們將會通過 requestModel.Start 追蹤用戶點擊的每一個頁面。requestModel.Length 將會告訴用戶查看的頁面有多少行數據,這個用戶可以使用頁面中的 combo 框來進行配置。

在服務器端實現表格的過濾、分頁和排序等功能,能夠減少客戶端數據處理的任務量,方便更好更快的加載並顯示數據。表格控件是項目開發中經常用到的控件,其中以性能著稱的是FlexGrid表格控件,這是一款輕量級的高性能表格控件,加載和滾動速度比競爭對手快10倍以上,能提供豐富的功能集,而不膨脹核心控件。

現在 build 這個工程並在瀏覽中運行,就可以查看帶有服務器端過濾、分頁和排序的 GridView 了。

文章來源:by Ehsan Sajjad

原文鏈接:http://www.codeproject.com/Articles/1118363/GridView-with-Server-Side-Filtering-Sorting-and-Pa

發佈了7 篇原創文章 · 獲贊 1 · 訪問量 8913
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章