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
中的Linq
Where
):

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();
}