Linq调用select语句中的方法非常慢

问题描述:

我想要找到是否有方法从我的linq select语句中调用一个方法来构建一个不会显着减慢速度的对象列表。这背后的原因是我也想调用相同的方法,当试图获得只有一个对象,并不想保持两个版本(即如果我有另一个字段添加到对象或想呈现其中之一不同的领域,我不会改变它在多个地方)。Linq调用select语句中的方法非常慢

// Start timer 
var timer = new Stopwatch(); 
timer.Start(); 

var test = (from job in dc.Jobs 
     where !job.archived 
     select new JobExtended() 
     { 
      JobId = job.jobId, 
      NodeId = job.nodeId, 
      JobName = job.name != string.Empty ? job.name : "TBC", 
      Salary = job.salary, 
      RecruiterId = job.fkRecruiterId, 
      RecruiterNodeId = job.JobRecruiter != null ? job.JobRecruiter.recruiterNodeId : null, 
      RecruiterName = job.JobRecruiter != null ? job.JobRecruiter.name : string.Empty, 
      LocationId = job.fkLocationId, 
      Location = job.refJobLocation != null ? job.refJobLocation.jobLocation : "", 
      ContractTypeId = job.fkContractTypeId, 
      ContractType = job.refJobContractType != null ? job.refJobContractType.contractType : "", 
      CategoryId = job.fkCategoryId, 
      Category = job.refJobCategory != null ? job.refJobCategory.category : "", 
      ClosingDate = job.closingDate, 
      Featured = job.featured, 
      JobOfTheWeek = job.jobOfTheWeek, 
      PublishedDate = job.publishedDate, 
      Url = "/jobs/" + job.name.Replace(" ", "-").Replace("&", "and").Replace("'", "") + (job.fkLocationId.HasValue ? "-in-" + job.refJobLocation.jobLocation.Replace(" ", "-").Replace("&", "and").Replace("'", "") : "") + "-jn" + job.jobId, 
      CreatedOn = job.createdOnDate, 
      PrintWidth = job.printWidth, 
      PrintHeight = job.printHeight, 
      UntilFilled = (job.untilFilled != null && job.untilFilled.Value), 
      AdvertCost = job.advertCost, 
      DatesToShow = job.relJobDates.Where(x => x.fkJobId == job.jobId).Select(x => x.date).ToList(), 
      IsParentJob = job.relLinkedJobs != null && job.relLinkedJobs.Any(x => x.fkParentJobId == job.jobId), 
      IsAlternateWeekJob = job.alternateWeek != null && job.alternateWeek.Value, 
      Archived = job.archived, 
      LastModifiedDate = job.lastModifiedDate, 
      RecruiterContactDetails = job.recruiterContactDetails 
     }).ToList(); 

// Stop timer 
timer.Stop(); 

// Output info 
litTest.Text = "TEST 1 in " + timer.Elapsed.TotalSeconds + " seconds<br/>"; 

//Start timer 
timer = new Stopwatch(); 
timer.Start(); 

var test2 = (from job in dc.Jobs 
      where !job.archived 
      select GetJobDetails(job)).ToList(); 

//Stop timer 
timer.Stop(); 

//Output info 
litTest.Text += "TEST 2 in " + timer.Elapsed.TotalSeconds + " seconds<br/>"; 

这是测试2正在呼叫应当创建了在TEST 1被返回的相同对象的方法:比试验2更快

在下面的例子中,TEST 1个行驶超过100倍:

public static JobExtended GetJobDetails(Data.Job job) 
{ 
    return new JobExtended() 
    { 
     JobId = job.jobId, 
     NodeId = job.nodeId, 
     JobName = job.name != string.Empty ? job.name : "TBC", 
     Salary = job.salary, 
     RecruiterId = job.fkRecruiterId, 
     RecruiterNodeId = job.JobRecruiter != null ? job.JobRecruiter.recruiterNodeId : null, 
     RecruiterName = job.JobRecruiter != null ? job.JobRecruiter.name : string.Empty, 
     LocationId = job.fkLocationId, 
     Location = job.refJobLocation != null ? job.refJobLocation.jobLocation : "", 
     ContractTypeId = job.fkContractTypeId, 
     ContractType = job.refJobContractType != null ? job.refJobContractType.contractType : "", 
     CategoryId = job.fkCategoryId, 
     Category = job.refJobCategory != null ? job.refJobCategory.category : "", 
     ClosingDate = job.closingDate, 
     Featured = job.featured, 
     JobOfTheWeek = job.jobOfTheWeek, 
     PublishedDate = job.publishedDate, 
     Url = "/jobs/" + job.name.Replace(" ", "-").Replace("&", "and").Replace("'", "") + (job.fkLocationId.HasValue ? "-in-" + job.refJobLocation.jobLocation.Replace(" ", "-").Replace("&", "and").Replace("'", "") : "") + "-jn" + job.jobId, 
     CreatedOn = job.createdOnDate, 
     PrintWidth = job.printWidth, 
     PrintHeight = job.printHeight, 
     UntilFilled = (job.untilFilled != null && job.untilFilled.Value), 
     AdvertCost = job.advertCost, 
     DatesToShow = job.relJobDates.Where(x => x.fkJobId == job.jobId).Select(x => x.date).ToList(), 
     IsParentJob = job.relLinkedJobs != null && job.relLinkedJobs.Any(x => x.fkParentJobId == job.jobId), 
     IsAlternateWeekJob = job.alternateWeek != null && job.alternateWeek.Value, 
     Archived = job.archived, 
     LastModifiedDate = job.lastModifiedDate, 
     RecruiterContactDetails = job.recruiterContactDetails 
    }; 
} 

这样做的原因是因为我希望能够调用“GetJobDetails”例如用于返回一个作业:

public JobExtended GetJobDetails(int jobId) 
    { 
     using (DataContext dc = new DataContext()) 
     { 
      return dc.Jobs.Where(x => x.jobId == jobId).Select(j => GetJobDetails(j)).FirstOrDefault(); 
     } 
    } 

这样做会让我只需要更新“GetJobDetails”方法,例如,如果我决定添加一个新的变化字段,如何生成“Url”值,但这样做的速度会慢很多。有没有解决的办法,我已经尝试过这似乎并没有帮助的情况如下:我以前见过这种问题

var test3 = (from job in dc.Jobs 
       where !job.archived 
       select job).AsEnumerable() 
       .Select(GetJobDetails).ToList(); 

var test4 = (from job in dc.Jobs 
       where !job.archived 
       select GetJobDetails(job)); 
var test4a = test4.ToList(); 
+0

JobExtended'的'构造函数应该只有一个参数,这就是'Data.Job'。分配属性和检查其他东西应该在构造函数内完成。我说这是因为你有很多属性。你的代码将被缩减为'返回新的JobExtended(工作);'....你在一行中做得太多了。这就是我想说的。 –

+0

@ M.kazemAkhgary您的解决方案将JobExtended类型构造函数与Job类型紧密耦合,这可能不合意。 – Svek

测试1的速度较快,原因是查询在服务器上执行一次,只返回选定的字段。

var test = (from job in dc.Jobs 
    where !job.archived 
    select new JobExtended() 
    { 
     JobId = job.jobId, 
     NodeId = job.nodeId, 
     ... 
    }).ToList(); 

当你调用TEST 2参数j需要GetJobDetails首先被物化,才能发送作为参数传递给GetJobDetails。所以有多个完整对象的调用。

return dc.Jobs.Where(x => x.jobId == jobId).Select(j => GetJobDetails(j)).FirstOrDefault(); 

为了达到像你想要的东西,你应该使用扩展方法。这个扩展了IQueryable。

public static IEnumerable<JobExtended> SelectJobExtended(this IQueryable<Data.Job> query) 
    { 
     return query 
      .Select(o => new JobExtended() 
      { 
       JobId = job.jobId, 
       NodeId = job.nodeId, 
       ... 
      } 
    } 

然后,您可以拨打:

dc.Jobs.Where(x => x.jobId == jobId).SelectJobExtended().FirstOrDefault(); 
+0

我尝试这样做,但我接收到“SelectJobExtended”方法中的以下错误: **其他信息:无法翻译表达“表(作业)。凡(X =>未(x.archived))”到SQL和不能把它当作本地表达式。** – trfletch

+0

它应该是.Select(job => new JobExtended()... {..}); – Svek

+0

IList应该是IEnumerable。我已经更新了答案。 –

。如果我记得,我们所做的是“堆积”查询。

public IEnumerable<JobExtended> ConvertToJobExtended(IEnumerable<Job> jobs) 
{ 
    return 
     from job in jobs 
     select new JobExtended() 
     { 
      MyString = job.MyInt.ToString(), 
      ... 
     }; 
} 

你可以做那么什么是调用它的方式如下:

var query = (from job in dc.Jobs 
     where !job.archived 
     select job; 

var test2 = ConvertToJobExtended(query).ToList(); 

有很多替代品,可以从这里去...我希望这正好在你的正确方向正在寻找。

+0

我试过这个,但它似乎并没有改善性能。 – trfletch

+0

您使用IEnumerable 还是IQueryable ?另外请注意,ToList()只被调用一次(最后)。 – Svek