我已经学习了几个月的C#/ LINQ / ASP.NET / MVC 3 / EF,现在来自Java / Icefaces / Ibatis基础(真实世界使用.NET D;)。我非常喜欢.NET Framework中的LINQ / Entity Framework,但是我有一些问题需要了解幕后真正发生的事情。
这是我的问题:
我正在使用AJAX / JSON fed jQuery datatable(我强烈建议任何需要免费网络数据表系统的人)。我在我的MVC3应用程序中有一个方法,它返回表所需数据的JSON结果,进行排序等等。一切都很顺利。但是,我对我必须做的“肮脏”黑客有所顾虑。
这是完整的代码:
//inEntities is the Entity Framework Database Context
//It includes the following entities:
// Poincon
// Horaire
// HoraireDetail
//Poincon, Horaire and HoraireDetail are "decorated" using the Metadata technic which
//adds properties methods and such to the Entity (Like getEmploye which you will see in
//the following snippet)
//
//The Entity Employe is not a database data and therefor not handled by the EF.
//Instead, it is a simple object with properties that applies Lazy Loading to get an
//Employe Name based off of his Employe ID in the Active Directory. An employe object
//can be constructed with his Employe ID which will expose the possibility of getting
//the Employe Name from the AD if needed.
[HttpPost]
public JsonResult List(FormCollection form)
{
String sEcho;
int iDisplayStart;
int iDisplayLength;
String sSearch;
int iSortingCols;
Dictionary<String, String> sorting;
try
{
sEcho = form["sEcho"];
iDisplayStart = int.Parse(form["iDisplayStart"]);
iDisplayLength = int.Parse(form["iDisplayLength"]);
sSearch = form["sSearch"];
iSortingCols = int.Parse(form["iSortingCols"]);
sorting = new Dictionary<string,string>();
for (int i = 0; i < iSortingCols; i++)
sorting.Add(form["mDataProp_" + form["iSortCol_" + i]].ToUpper(), form["sSortDir_" + i].ToUpper());
}
catch
{
HttpContext.Response.StatusCode = 500;
return null;
}
var qPoincon = inEntities.Poincons.AsEnumerable();
var lPoincon = qPoincon.Select(o => new
{
o.id,
emp = o.getEmploye(),
o.poinconStart,
o.poinconEnd,
o.commentaire,
o.codeExceptions
}).AsEnumerable();
//Search
lPoincon = lPoincon.Where(p => (p.emp.empNoStr.Contains(sSearch) || p.emp.empNom.Contains(sSearch) || (p.commentaire != null && p.commentaire.Contains(sSearch))));
//Keep count
int iTotalDisplayRecords = lPoincon.Count();
//Sorting
foreach(KeyValuePair<String,String> col in sorting)
{
switch (col.Key)
{
case "EMPNO":
if (col.Value == "ASC")
lPoincon = lPoincon.OrderBy(h => h.emp.empNo);
else
lPoincon = lPoincon.OrderByDescending(h => h.emp.empNo);
break;
case "POINCONSTART":
if (col.Value == "ASC")
lPoincon = lPoincon.OrderBy(h => h.poinconStart);
else
lPoincon = lPoincon.OrderByDescending(h => h.poinconStart);
break;
case "POINCONEND":
if (col.Value == "ASC")
lPoincon = lPoincon.OrderBy(h => h.poinconEnd);
else
lPoincon = lPoincon.OrderByDescending(h => h.poinconEnd);
break;
case "COMMENTAIRE":
if (col.Value == "ASC")
lPoincon = lPoincon.OrderBy(h => h.commentaire);
else
lPoincon = lPoincon.OrderByDescending(h => h.commentaire);
break;
}
}
//Paging
lPoincon = lPoincon.Skip(iDisplayStart).Take(iDisplayLength);
//Building Response
var jdt = new
{
iTotalDisplayRecords = iTotalDisplayRecords,
iTotalRecords = inEntities.Poincons.Count(),
sEcho = sEcho,
aaData = lPoincon
};
return Json(jdt);
}
正如你所看到的,当我从EF中抓取整个“Poincons”列表并将其变成Enumerable时。根据我目前的理解,将LINQ查询转换为Enumerable“杀死”到EF的链接,或者换句话说,将生成在该点获取该列表所需的SQL,而不是将LINQ数据保留到最后并执行percise查询,只返回您需要的数据。在将此LINQ查询转换为Enumerable之后,我对LINQ进行了大量过滤(因为在数据表中存在分页,排序和搜索)。这让我想到我的代码目前正在做的是“从数据库中抓取所有”Poincons“并将其作为Enumerable放入Web服务器的内存中,使用Enumerable进行工作,然后将结果序列化为JSON字符串,发送给客户。
如果我是正确的,那么当您点击几千个条目时,性能就会非常沉重(一旦投入生产就会很快发生......每当一个员工上班时,它将增加1个条目.100个雇员,每年约300个工作日,你明白了。)
这种黑客的原因是EF不知道“Poincon”的“getEmploye”方法是什么,因此在运行时抛出类似的异常:
LINQ to Entities ne reconnaît pas la méthode « PortailNorclair.Models.Employe getEmploye() », et cette dernière ne peut pas être traduite en expression de magasin.
近似转录(如果有人可以在评论中告诉我如何配置IIS / ASP.NET以显示英语错误,同时保持全球化的外语,我会非常感激。有时会提供有关错误消息的法语信息缺乏):
LINQ to Entity does not recognize the method " PortailNorclair.Models.Employe getEmploye()" and the following could not be translated to a SQL expression.
“getEmploye”方法实例并返回一个Employe对象,该对象具有在Poincon对象中找到的employees id。 Employe对象具有“延迟加载”信息的属性,例如来自Active Directory的雇员名称。
所以问题是:如何在未经过滤的对象列表中使用.AsEnumerable()来避免性能损失?
非常感谢!
答案 0 :(得分:1)
“getEmploye”方法实例并返回一个Employe对象 在Poincon对象中找到的雇员id。那个Employe对象有 “延迟加载”信息的属性,如来自的员工姓名 Active Directory。
您应该将Employee Name存储在数据库中,这样您就可以对Linq Query进行排序,排序,跳过和接收,而无需加载每个员工对象。
如果empNoStr,empNom和empNo都在数据库中,您可以只检索所需的记录,并为每个记录调用getEmploye()(从活动目录或其他任何地方加载任何其他内容)。
答案 1 :(得分:0)
您的计划有一些课程可以完成其主要工作。
还有其他类代表数据库行。
如果将它们分开,您还可以将要在数据库中执行的操作与要在本地执行的操作分开。这使得在需要特定行时避免加载完整表格变得微不足道。
我看到你也在本地进行Paging,而数据库可以做到这一点,并为你的web服务器节省一些内存。