查看需要3分钟才能加载

时间:2014-01-06 11:21:13

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

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

好的我在我的控制器中有一个动作结果,目的是采用许多不同的服务和模型,并将数据去规范化为列表以供显示视图,这是基于用户交互的简单控件用于过滤数据。

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

现在这个控制器功能工作得相当好,直到我在代码中添加了传递的每个模块。我原本想和旧项目一样做,加入数据然后交叉查询去标准化结果然后再使用。

然而,当我首先从SQL转换为代码时,我不确定是否或如何模仿交叉查询。

这导致我创建了很多循环。 这是控制器动作方法和非动作。

 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列代表模块,如果通过或未通过。

正如我所说,当我添加代码以获取传递或未传递的布尔值时,我的查询已被拍摄并且需要很长时间。

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

感谢您的提示!

更新::

继承人的个人资料结果,因为在我不确定我在这里看到什么之前我从未使用过这个。

Profile

注释掉“if(groupedModules.Count&gt; 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秒。 然而,众所周知,这仍然很慢,唯一的结论是这个代码必须位于选择列表中。那么有没有办法重做这个过程?

2 个答案:

答案 0 :(得分:2)

快速猜测:当您执行组查询时,数据仍处于查询形式。 EF上的GroupBy()具有如此糟糕的性能,以至于强迫它首先列出的速度要快得多。

长答案比快速猜测要短得多:简介!

答案 1 :(得分:1)

var historyResults = quizHistoryQuery.ToList();

看起来你正在执行这个查询并将结果存储在一个列表中,但是你正在做几行:

var thisHistory1 = quizHistoryQuery.Where(y => y.User.Id == x.Id && moduleIds1.Contains(y.Module.Id));

导致查询再次执行。

这只是弹出的东西,我不知道它是否会导致你的减速。无论如何,请重新检查您可能运行相同查询两次的任何实例,因为它似乎是在几个地方执行此操作。考虑将结果存储在列表中,然后再使用它们。 还要考虑启动SQL事件探查器,看看生成的SQL查询的外观以及哪一个花费的时间最多。