c# - 查看加载时间超过 3 分钟

标签 c# asp.net-mvc-4 nhibernate code-first

使用asp.net MVC 4.0 c#,Visual Studio 2012 Professional。

好的,我的 Controller 中有一个操作结果,目的是采用许多不同的服务和模型,并将数据非规范化为列表以供 View 显示,这是基于通过以下方式进行的用户交互简单的控件用于过滤数据。

整个网站已从 Webforms Sql 项目迁移到使用内部 CMS 解决方案的 MVC 代码优先方法(cms 基于 Nop commerce 和 Orchard)。

现在这个 Controller 功能工作得相当好,直到我为每个通过的模块添加代码。我最初想像处理旧项目一样,加入数据,然后交叉查询以获取要使用的非规范化结果。

但是,当我首先从 SQL 转移到代码时,我不确定是否或如何模拟交叉查询。

这导致我创建了很多循环。 这是 Controller 操作方法和非操作方法。

 public ActionResult Index(UsersModel model) 
    {
        model.DateTo = model.DateTo.AddDays(1);

        if (model.DateFrom == null || model.DateTo == null || model.DateFrom == DateTime.MinValue || model.DateTo == DateTime.MinValue.AddDays(1))
        {
            // default to last 30 days
            model.DateFrom = _clock.UtcNow.AddDays(-30);
            model.DateTo = _clock.UtcNow;
        }

        var userQuery = _academyUserService.Query()
            .Where(x => x.Activity.DateRegistered >= model.DateFrom && x.Activity.DateRegistered <= model.DateTo);

        var quizCompletedQuery = _quizService.QueryQuizHistoryCompleted()
            .Where(x => x.DateCompleted >= model.DateFrom && x.DateCompleted <= model.DateTo);

        var quizHistoryQuery = _quizService.QueryHistory()
            .Where(x => x.DateCompleted >= model.DateFrom && x.DateCompleted <= model.DateTo);

        var moduleQuery = _moduleService.Query()
            .Where(x => x.Published);

        //admin country selected, null = global
        if (_moServices.WorkContext.HttpContext.Session["AdminAreaCurrentCulture"] != null)
        {
            userQuery = userQuery.Where(x => x.UserCountry.CountryCulture.Culture == _moServices.WorkContext.HttpContext.Session["AdminAreaCurrentCulture"].ToString());
            quizCompletedQuery = quizCompletedQuery.Where(x => x.Country.CountryCulture.Culture == _moServices.WorkContext.HttpContext.Session["AdminAreaCurrentCulture"].ToString());
            quizHistoryQuery = quizHistoryQuery.Where(x => x.Module.Country.CountryCulture.Culture == _moServices.WorkContext.HttpContext.Session["AdminAreaCurrentCulture"].ToString());
            moduleQuery = moduleQuery.Where(x => x.Country.CountryCulture.Culture == _moServices.WorkContext.HttpContext.Session["AdminAreaCurrentCulture"].ToString());
        }

        if (!string.IsNullOrEmpty(model.Name))
        {
            userQuery = userQuery.Where(x => x.FirstName.Contains(model.Name) || x.Surname.Contains(model.Name));
        }

        if (!string.IsNullOrEmpty(model.AccountType))
        {
            userQuery = userQuery.Where(x => x.AccountType.ToString() == model.AccountType);
        }

        if (!string.IsNullOrEmpty(model.Company))
        {
            userQuery = userQuery.Where(x => x.BusinessName == model.Company);//placeholder intefering with this?
        }

        if (!string.IsNullOrEmpty(model.Code))
        {
            userQuery = userQuery.Where(x => x.RegistrationCode.Contains(model.Code));
        }

        if(true)//cant condition an Iquery as its not a list...)//temp
        {
            //quizCompletedQuery = quizCompletedQuery.Where(x => x.Country.CountryCulture.Culture == _moServices.WorkContext.HttpContext.Session["AdminAreaCurrentCulture"].ToString());
        }

        //new code
        var groupedModules = moduleQuery
             .OrderBy(x => x.DisplayOrder)
             .ToList()
             .GroupBy(x => x.Country)
             .SelectMany(group => group.Select((x, i) => new { Index = i, Module = x }))
             .GroupBy(anon => anon.Index)
             .Select(group => group.Select(x => x.Module).ToList())
             .ToList();

        var historyResults = quizHistoryQuery.ToList();

        //my old code
        PrepareBusinessNames(model);

        var usersToModel = userQuery.ToList().Select(x =>
        {

            bool thisHistoryPassed1 = false;
            bool thisHistoryPassed2 = false;
            bool thisHistoryPassed3 = false;
            bool thisHistoryPassed4 = false;

            if (groupedModules.Count > 0)
            {
                var module1 = groupedModules[0];
                var moduleIds1 = module1.Select(y => y.Id).ToList();
                var thisHistory1 = quizHistoryQuery.Where(y => y.User.Id == x.Id && moduleIds1.Contains(y.Module.Id));
                thisHistoryPassed1 = thisHistory1.Any(_quizService.IsHistoryPassed);
            }

            if (groupedModules.Count > 1)
            {
                var module2 = groupedModules[1];
                var moduleIds2 = module2.Select(y => y.Id).ToList();
                var thisHistory2 = quizHistoryQuery.Where(y => y.User.Id == x.Id && moduleIds2.Contains(y.Module.Id));
                thisHistoryPassed2 = thisHistory2.Any(_quizService.IsHistoryPassed);
            }

            if (groupedModules.Count > 2)
            {
                var module3 = groupedModules[2];
                var moduleIds3 = module3.Select(y => y.Id).ToList();
                var thisHistory3 = quizHistoryQuery.Where(y => y.User.Id == x.Id && moduleIds3.Contains(y.Module.Id));
                thisHistoryPassed3 = thisHistory3.Any(_quizService.IsHistoryPassed);
            }

            if (groupedModules.Count > 3)
            {
                var module4 = groupedModules[3];
                var moduleIds4 = module4.Select(y => y.Id).ToList();
                var thisHistory4 = quizHistoryQuery.Where(y => y.User.Id == x.Id && moduleIds4.Contains(y.Module.Id));
                thisHistoryPassed4 = thisHistory4.Any(_quizService.IsHistoryPassed);
            }

            return new UsersSearchModel
            {
                UserID = x.Id,
                Name = x.FirstName,
                Surname = x.Surname,
                Company = x.BusinessName,
                AccountType = x.AccountType.ToString(),
                UserCode = x.RegistrationCode,
                VideosViewed = "", //x.VideoActivity.ToString(), 
                Module1 = thisHistoryPassed1,
                Module2 = thisHistoryPassed2,
                Module3 = thisHistoryPassed3,
                Module4 = thisHistoryPassed4,
                Module1Url = thisHistoryPassed1 ? Url.Content("~/Areas/Admin/Media/Images/checked.png") : Url.Content("~/Areas/Admin/Media/Images/unchecked.png"),
                Module2Url = thisHistoryPassed2 ? Url.Content("~/Areas/Admin/Media/Images/checked.png") : Url.Content("~/Areas/Admin/Media/Images/unchecked.png"),
                Module3Url = thisHistoryPassed3 ? Url.Content("~/Areas/Admin/Media/Images/checked.png") : Url.Content("~/Areas/Admin/Media/Images/unchecked.png"),
                Module4Url = thisHistoryPassed4 ? Url.Content("~/Areas/Admin/Media/Images/checked.png") : Url.Content("~/Areas/Admin/Media/Images/unchecked.png")
            };
        }).ToList();

        var jsonSerialiser = new JavaScriptSerializer();
        var jsonString = jsonSerialiser.Serialize(usersToModel);//or is it model? or a list of model?
        model.REFACTOR_ForJson = jsonString;

        return View(model);
    }

    #region utilities

    [NonAction]
    private UsersModel PrepareBusinessNames(UsersModel model)
    {
        if (_moServices.Authoriser.Authorise(DefaultPermissions.AccessAdminPanel))
        {
            var listItems = _academyUserService.GetAllBusinessNames().Select(x =>
            {
                return new SelectListItem
                {
                    Value = x,
                    Text = x
                };
            }).OrderBy(x => x.Value)
            .ToList();

            model.CurrentBusinessNames = new SelectList(listItems, "Value", "Text");
        }

        return model;
    }

如您所见,我想返回一个用户列表,并根据过滤器显示该列表,其中 4 列代表模块以及是否通过。

正如我所说,当我添加代码来获取通过或未通过的 bool 值时,我的查询已被执行并且需要很长时间。

那么,有没有办法通过调整现有代码来解决问题,或者是否可以使用与交叉查询类似的方法来重写功能?

谢谢各位的指点!

更新::

这是配置文件结果,因为我之前从未使用过它,所以我不确定我在这里看到的是什么。

Profile

注释掉“if(groupedModules.Count > 0)”部分和其他 If 语句,这显然是导致响应缓慢的原因。正如我之前问过的,有没有更好的方法来实现我的结果?

更新::替换

if (groupedModules.Count > 0)
            {
                var module1 = groupedModules[0];
                var moduleIds1 = module1.Select(y => y.Id).ToList();
                var thisHistory1 = quizHistoryQuery.Where(y => y.User.Id == x.Id && moduleIds1.Contains(y.Module.Id));
                thisHistoryPassed1 = thisHistory1.Any(_quizService.IsHistoryPassed);
            }

if (groupedModules.Count > 0)
            {
                var module1 = groupedModules[0];
                var moduleIds1 = module1.Select(y => y.Id).ToList();
                var thisHistory1 = historyResults.Where(y => y.User.Id == x.Id && moduleIds1.Contains(y.Module.Id));
                thisHistoryPassed1 = thisHistory1.Any(_quizService.IsHistoryPassed);
            }

我不使用 iquerable,而是列出历史记录,然后使用列表。 这显着缩短了加载时间,从 6 分钟缩短到 15 秒。 然而,众所周知,这仍然很慢,唯一的结论是该代码必须位于选择列表中。那么有没有办法重做这个过程呢?

最佳答案

快速猜测:当您执行组查询时,数据仍然处于查询形式。 EF 上的 GroupBy() 性能非常糟糕,强制它先列出要快得多。

长答案比快速猜测要短得多:个人资料!

关于c# - 查看加载时间超过 3 分钟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20948926/

相关文章:

c# - 是double还是double?可互换?

c# - 如何使用SqlConnection 执行带注释的SQL 和GO 语句?

c# - HttpContext.Current.Response.AddHeader() 未设置 Content-Type header

C# List<int> 从 SQL 存储过程结果填充

asp.net-mvc-4 - 上传时如何捕获azure blob引用

c# - NHibernate:单个事务上的多次提交

c# - 在使用 Fluent NHibernate 映射时对接口(interface)进行编程

javascript - JQuerysiblings.data() 不返回正确的值

c# - 如何在 WebApi 中添加和获取 Header 值

nhibernate - 在 NHibernate 中的映射级别过滤实体