C#优化代码
我有以下函数,它返回一个C#优化代码,c#,linq,optimization,C#,Linq,Optimization,我有以下函数,它返回一个模型。这需要时间,比如说如果有2000名员工,则返回数据需要3-4分钟。我实际上想优化这个函数。我做了一些包含在下面代码中的事情,但仍然需要很多时间 using (var ctx = new ApplicationDbContext(schemaName)) { List<Employee> list = new List<Employee>(); Employee mod = new
模型
。这需要时间,比如说如果有2000名员工
,则返回数据需要3-4分钟。我实际上想优化这个函数。我做了一些包含在下面代码中的事情,但仍然需要很多时间
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;
}
}
使用(var ctx=newapplicationdbcontext(schemaName))
{
列表=新列表();
Employee mod=新员工();
var data=ctx.Employee.Where(a=>a.Company==comp&&a.Status==Live)
.选择(a=>新建
{
Id=a.Id,
代码=a.代码,
FName=a.FName,
DateOfJoining=a.DateOfJoining,
类别=a.类别,
系,
名称=a.名称;
})
.ToList();
var loadValues=ctx.CValue.Where(c=>c.Company==comp.ToList();
foreach(数据中的var项)
{
mod=新员工();
mod.Id=item.Id;
mod.Code=物料代码;
mod.FName=item.FName;
mod.DateOfJoining=item.DateOfJoining;
mod.Category=物料类别;
型号名称=项目名称;
mod.Department=项目部门;
内部名称=(项目名称==空)?0:项目名称;
int department=(item.department==null)?0:item.department;
如果(名称!=0)
mod.DesignationString=loadValues。其中(c=>c.CompanyId==comp&&c.Id==designation)。选择(c=>c.ComboValue)。FirstOrDefault();
如果(部门!=0)
mod.DepartmentString=loadValues.Where(c=>c.Company==comp&&c.Id==department)。选择(c=>c.ComboValue.FirstOrDefault();
列表。添加(mod);
}
退货清单;
}
}
我认为是foreach
循环需要时间。有什么解决方法吗?如何优化上述代码 您可以通过使用快速查找数据结构来优化嵌套循环(在foreach
中的LinqWhere
):
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块中是多余的,因为它已经是初始查询的一部分。我已将代码优化为一个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);
});
}
以下截取可能需要相当长的时间(当然要进行性能测量)
因为loadValues
是一个总是按顺序搜索的列表。因此,根据loadValues
的大小,此列表中可能会有大量搜索。此外,您不需要比较CompanyId
,因为您已经在loadValues
的定义中按CompanyId
进行了筛选
要加快这里的速度,可以使用查找
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
进行搜索时,您还可以创建一个简单的字典
我会这样写:
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();
}
但我假设您有一个带有适当的外键的DB结构,名称是引用表CValue的列。没有嵌套循环,没有加倍的内存分配(正如我在评论中提到的),所有内容都将使用连接获得,这比Where子句快得多
编辑您需要返回与映射实体不同的模型列表。请看我的示例的第8行。如果您尝试运行。选择(e=>newemployee())
,您将得到注释中提到的错误。(更多信息请点击此处:)
但是如果您返回List
,您可以在应用程序上层的任何地方使用该列表,您可以添加更多的元素(它们可以是DB查询以外的其他方法的结果,例如XML导入),并且您将独立于实际的DB映射类
您可以在此处找到有关应用程序组合的更多信息:。ctx是如何填充的?你提供的代码不应该花那么长的时间。如何使用秒表,一行一行地测量时间?为什么你
将某些短语
格式化为代码
,而它们不是真正的代码?实际花费时间的是linq WHERE。linq生成一个枚举。每次通过for循环时,都会找到Linq中的下一项。每个员工需要1/4秒(2000年为4分钟),这并不太糟糕,尤其是当你从数据库中获取数据时。也许可以先找到你的公司。因为您使用的是Linq,所以可以使用companystance.Employees
。这将作为更快的join执行。我相信你不需要有var数据
,因为List
,IQueryable
就足够了,你将避免获得整个列表,并用几乎相同的值重新创建新的列表。这在顺序列表上做了几乎相同的子查询,所以我认为没有太大区别。它可能会稍微快一点,但没有实质性的好处。我得到了错误实体或复杂类型的“模型”。Employee不能在LINQ to Entities查询中构造。
我得到了错误,实体或复杂类型的“模型”。Employee不能在LINQ to Entities查询中构造。@Anup我扩展了我的答案。我希望有帮助。
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;
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();
}