jQuery DataTable 和 MVC 服务器端处理

jQuery DataTable and MVC server side processing

所以我在 MVC 中为 jQuery 数据 table 实现了服务器端处理,我正在显示 1 to 10 of 8,037 entries(带分页)。但是,当我导航到带有 table 的页面时,第一次加载需要很长时间(5 到 10 秒)。在我的控制器中,我将其设置为仅记录 10 条记录 (iDisplayLength):

        var displayedProviders = filteredProviders
            .Skip(param.iDisplayStart)
            .Take(param.iDisplayLength);

因此,当我第一次使用 table 导航到页面或使用分页时,它应该一次只能加载 10 条记录。

谁能告诉我为什么第一次加载需要这么长时间?我担心的是它将整个 table 加载到 Json 请求中,这首先会减慢它的速度。这不是我在实施服务器端处理时想到的。有没有解决的办法?如果我实施:

    var model = _db.CareProviders
.OrderBy(row => row.ProviderId).Skip((pageNumber - 1) * pageResults)
    .Take(pageResults).ToList();

这只会显示 10 个结果,不会更多?

型号:

    public class jQueryDataTableParamModel
    {
        /// <summary>
        /// Request sequence number sent by DataTable,
        /// same value must be returned in response
        /// </summary>       
        public string sEcho { get; set; }

        /// <summary>
        /// Text used for filtering
        /// </summary>
        public string sSearch { get; set; }

        /// <summary>
        /// Number of records that should be shown in table
        /// </summary>
        public int iDisplayLength { get; set; }

        /// <summary>
        /// First record that should be shown(used for paging)
        /// </summary>
        public int iDisplayStart { get; set; }

        /// <summary>
        /// Number of columns in table
        /// </summary>
        public int iColumns { get; set; }

        /// <summary>
        /// Number of columns that are used in sorting
        /// </summary>
        public int iSortingCols { get; set; }

        /// <summary>
        /// Comma separated list of column names
        /// </summary>
        public string sColumns { get; set; }
    }
}

控制器:

    public ActionResult AjaxHandler(jQueryDataTableParamModel param)
    {
        var allProviders = _db.CareProviders.ToList();
        IEnumerable<CareProvider> filteredProviders;

        if (!string.IsNullOrEmpty(param.sSearch))
        {
            filteredProviders = _db.CareProviders.ToList()
                     .Where(c => c.ProviderId.Contains(param.sSearch)
                                 ||
                      c.CareServiceType.Contains(param.sSearch)
                                 ||
                                 c.CareServiceName.Contains(param.sSearch));
        }
        else
        {
            filteredProviders = allProviders;
        }
        var displayedProviders = filteredProviders
            .Skip(param.iDisplayStart)
            .Take(param.iDisplayLength);

        var result = from c in displayedProviders
                     select new[] { Convert.ToString(c.ProviderId), c.CareServiceType, c.CareServiceName, c.Email };
        return Json(new
        {
            sEcho = param.sEcho,
            iTotalRecords = allProviders.Count(),
            iTotalDisplayRecords = filteredProviders.Count(),
            aaData = result
        },
                         JsonRequestBehavior.AllowGet);

    }

Jquery 数据表脚本:

<script type="text/javascript">
    $(function () {
        // Initialize Example 2
        // $('#example2').dataTable();
        $('#example2').dataTable({
            "bServerSide": true,
            "sAjaxSource": "AdminPanel/AjaxHandler",
            "bProcessing": true,
            "aoColumns": [
                            { "sName": "ProviderId" },
                            { "sName": "CareServiceType" },
                            { "sName": "CareServiceName" },
                            { "sName": "Email" }
            ]
        });
    });
</script>

在 AjaxHandler 方法的第一行中,有 var allProviders = _db.CareProviders.ToList(); 将从 table 加载所有内容。是大号的吗? ... 如果是,那是你的问题。

另外,行 filteredProviders = _db.CareProviders.ToList() 将从 table 加载 一切 并将其具体化。 Where 将在物化数据上执行,并且代码后面的 Take 方法将从已经物化的数据中取出一小部分(同样的原因)。

是数据库中的选择和实现时间比较长。

我认为这不是数据表问题。在您的代码中,第一行 var allProviders = _db.CareProviders.ToList(); 立即访问您的数据库并将所有提供程序加载到内存中。只有在加载到内存中之后,您才会使用 skip 和 take 进行过滤,因此您会遇到初始查询执行开销。更糟糕的是,如果您有过滤条件,您 运行 filteredProviders = _db.CareProviders.ToList() 会访问您的数据库并重新执行整个操作。

记住,当 linq 使用延迟执行时,调用 ToList() 告诉它 "OK, I want this now." 它停止构建表达式树,访问数据库,并将结果转储到列表中,并完成任何进一步的过滤在列表本身上。

你的初始前提是正确的。 运行ning var model = _db.CareProviders .OrderBy(row => row.ProviderId).Skip((pageNumber - 1) * pageResults) .Take(pageResults).ToList(); 确实只会 return 您想要的行,只要您使用的提供程序能够理解 skip and take(EF 可以)。

合并您的 allProvidersfilteredProviders 变量,仅在您应用所有可能的过滤器和跳过后才调用 ToList(),看看这是否会提高您的速度。