我有以下函数返回Model
。如果有2000 employees
则需要时间,需要3-4 minutes to return data
。我其实想要optimize this function
。我做了一些包含在下面的代码中的东西,但是它仍然需要很多时间。
using (var ctx = new ApplicationDbContext(schemaName))
{
List<Employee> list = new List<Employee>();
Employee mod = new Employee();
var data = ctx.Employee.Where(a => a.Company == comp && a.Status == Live)
.Select(a => new
{
Id = a.Id,
Code = a.Code,
FName = a.FName,
DateOfJoining = a.DateOfJoining,
Category = a.Category,
Department = a.Department,
Designation = a.Designation;
})
.ToList();
var loadValues = ctx.CValue.Where(c => c.Company == comp).ToList();
foreach (var item in data)
{
mod = new Employee();
mod.Id = item.Id;
mod.Code = item.Code;
mod.FName = item.FName;
mod.DateOfJoining = item.DateOfJoining;
mod.Category = item.Category;
mod.Designation = item.Designation;
mod.Department = item.Department;
int designation = (item.Designation == null) ? 0 : item.Designation;
int department = (item.Department == null) ? 0 : item.Department;
if (designation != 0)
mod.DesignationString = loadValues.Where(c => c.CompanyId == comp && c.Id == designation).Select(c => c.ComboValue).FirstOrDefault();
if (department != 0)
mod.DepartmentString = loadValues.Where(c => c.Company == comp && c.Id == department).Select(c => c.ComboValue).FirstOrDefault();
list.Add(mod);
}
return list;
}
}
我认为这是花费时间的foreach
循环。对此有何解决方法?如何优化上述代码?
答案 0 :(得分:2)
您可以使用快速查找数据结构优化嵌套循环(Linq&#39; Where
内的foreach
):
var loadValues = (from c in ctx.CValues
where c.Company == comp
select c).ToLookup(x => Tuple.Create(x.CompanyId, x.ID),
x => x.ComboValue);
foreach (var item in data)
{
// your same code goes here
// then
if (designation != 0)
mod.DesignationString = loadValues[Tuple.Create(comp, designation)].FirstOrDefault();
if (department != 0)
mod.DepartmentString = loadValues[Tuple.Create(comp, department)].FirstOrDefault();
list.Add(mod);
}
我无法看到任何其他可以优化的部分。
值得注意的是comp
上的过滤器在if块中是多余的,因为它已经是初始查询的一部分。
答案 1 :(得分:2)
我已将代码优化为一个linq查询。我认为它会更快
using (var ctx = new ApplicationDbContext(schemaName))
{
var loadValues = ctx.CValue.Where(c => c.Company == comp).ToList();
return ctx
.Employee
.Where(a => a.Company == comp && a.Status == Live)
.Select(item => new Employee
{
Id = item.Id,
Code = item.Code,
FName = item.FName,
DateOfJoining = item.DateOfJoining,
Category = item.Category,
Designation = item.Designation,
Department = item.Department,
DesignationString = loadValues.Where(c => c.CompanyId == comp && c.Id == item.Designation ?? 0).FirstOrDefault(c => c.ComboValue);
DepartmentString = loadValues.Where(c => c.Company == comp && c.Id == item.Department ?? 0).FirstOrDefault(c => c.ComboValue);
});
}
答案 2 :(得分:2)
以下剪切可能需要很长时间(确保进行性能测量)
var loadValues = ctx.CValue.Where(c => c.Company == comp).ToList();
....
if (designation != 0) mod.DesignationString = loadValues.Where(c => c.CompanyId == comp && c.Id == designation).Select(c => c.ComboValue).FirstOrDefault();
if (department != 0) mod.DepartmentString = loadValues.Where(c => c.Company == comp && c.Id == department).Select(c => c.ComboValue).FirstOrDefault();
因为loadValues
是List
,总是按顺序搜索。因此,根据loadValues
的大小,此列表中可能会有大量搜索。此外,您无需比较CompanyId
,因为您已在CompanyId
的定义中按loadValues
进行了过滤。
为了加快这里的速度,您可以使用Lookup
。
var loadValues = ctx.CValue.Where(c => c.Company == comp).ToLookup(x=> x.Id);
if (designation != 0 && loadValues.Contains(designation)) mod.DesigationString = loadValues[designation].Select(c => c.ComboValue).FirstOrDefault();
if (department != 0 && loadValues.Contains(department)) mod.DepartmentString = loadValues[department].Select(c => c.ComboValue).FirstOrDefault();
或者,当您按Id
搜索哪个应该是唯一的时,您也可以制作一个简单的Dictionary<int, string>
。
var loadValues = ctx.CValue.Where(c=>c.Company == comp).ToDictionary(x=> x.Id, y=> y.ComboValue);
if (designation != 0) mod.DesigationString = loadValues.ContainsKey(designation) ? loadValues[designation] : String.Empty;
if (department != 0) mod.DepartmentString = loadValues.ContainsKey(department) ? loadValues[department] : String.Empty;
答案 3 :(得分:2)
using (var ctx = new ApplicationDbContext(schemaName))
{
var company = ctx.Companies.FirstOrDefault(e => e.ID == 42);
if(company == null)
throw new Exception();
var empl = company.Employees.Where(e=> e.Status == Live).Select(e=>
new EmployeeInfo{
ID = e.ID,
FName = e.FName,
//TODO
DesignationString = e.Designation != null ? e.Designation.ComboValue : string.Empty,
//TODO
});
return empl.ToList();
}
但是我假设您的数据库结构包含正确的外键而指定是列引用表 CValue 。没有嵌套循环,没有双倍的内存分配(正如我在评论中提到的),所有内容都将使用加入获得,这比 Where clausule更快。< / p>
编辑您需要返回与映射实体不同的模型列表。看看我的例子中的第8行。如果您尝试运行.Select(e => new Employee())
,则会在评论中收到错误消息。 (此处有更多信息:The entity cannot be constructed in a LINQ to Entities query。)
但是如果你返回List<EmployeeInfo>
,你可以使用该列表在应用程序的上层任何地方工作,你可以添加更多元素(它们可以是除DB查询之外的其他方法的结果,例如XML导入)并且您将独立于实际的DB映射类。
您可以在此处找到有关应用合成的更多信息:https://softwareengineering.stackexchange.com/questions/240704/confused-about-layered-application-development。