使用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列代表模块,如果通过或未通过。
正如我所说,当我添加代码以获取传递或未传递的布尔值时,我的查询已被拍摄并且需要很长时间。
那么,有没有办法通过调整现有代码来解决问题,或者是否可能使用与交叉查询类似的方法重写功能?
感谢您的提示!
更新::
继承人的个人资料结果,因为在我不确定我在这里看到什么之前我从未使用过这个。
注释掉“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秒。 然而,众所周知,这仍然很慢,唯一的结论是这个代码必须位于选择列表中。那么有没有办法重做这个过程?
答案 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查询的外观以及哪一个花费的时间最多。