【问题标题】:jQuery DataTable and MVC server side processingjQuery DataTable 和 MVC 服务器端处理
【发布时间】:2015-12-08 23:49:00
【问题描述】:

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

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

因此,当我第一次导航到包含表格的页面或使用分页时,它一次只能加载 10 条记录。

谁能指导我为什么第一次加载需要这么长时间?我担心它将整个表加载到 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 DataTable 脚本:

<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>

【问题讨论】:

    标签: c# jquery asp.net-mvc linq datatable


    【解决方案1】:

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

    请记住,当 linq 使用延迟执行时,调用 ToList() 会告诉它“好的,我现在就想要这个。”它会停止构建您的表达式树,访问您的数据库,并将结果转储到您的列表中,并且对列表本身进行任何进一步的过滤。

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

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

    【讨论】:

    • 如果我的数据库表是用提供者 id 索引的,我有没有办法一次从数据库中检索 10 条记录?然后使用索引进行分页,所以当我点击第 2 页时,它会将数据库中的下 10 条记录加载到我的数据表中?
    • 嗨,Garrith,您现在可能已经对此进行了测试,但这正是它的工作原理,假设数据表配置为在您单击第 2 页时访问服务器(并且您正在传递您需要服务器获取正确的记录)。如果您想在无需修改代码的情况下对自己的数据库进行 Linq 试验,Linqpad 是一款出色的工具。
    • 是的,我现在意识到这是服务器端速度问题。我最初认为服务器端将完整的 8000 条记录推送到客户端,这就是延迟的原因。我现在只是使用免费版本的 azure 来托管我的网站,并意识到它结合了糟糕的服务器端编码和免费 azure 网站的处理/内存问题。这就是我目前的理论。
    【解决方案2】:

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

    filteredProviders = _db.CareProviders.ToList() 行也将从表中加载 所有内容 并将其具体化。 Where 将在物化数据上执行,并且代码后面的 Take 方法将从已经物化的数据中获取一小部分(相同的原因)。

    是数据库的选择和物化需要很长时间。

    【讨论】:

    • 有什么建议可以优化这个吗?
    • 这里有两个有用的答案。你不明白什么?我将在此处引用Dmitri's answer:“合并您的allProvidersfilteredProviders 变量,并调用ToList()只有在您应用了所有可能的过滤器和您的skip and take之后,然后查看如果这能提高你的速度。”这正是您需要做的。我很乐意解释更多,但我不明白你不明白什么。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-29
    • 1970-01-01
    • 1970-01-01
    • 2018-05-16
    • 1970-01-01
    • 2021-08-14
    相关资源
    最近更新 更多