我有一个LINQ to Entity查询,它使用select将db中的原始数据转换为对象,在此过程中执行一些计算。计算重复了几次,所以我尝试重构LINQ来使用let。但是,这样做会严重影响性能。是否有替代LET的方法,我只能用于代码重用而不影响性能?
var defaultHours = 40;
var defaultOldPersonPoints = 100;
var defaultYoungPersonPoints = 50;
// Example with no let but lots of ugly, unreadable, redundant code
var exampleNoLet =
(from p in people
join op in otherPeople
on p.PersonId equals op.PersonId into inner
from outer in inner.DefaultIfEmpty(null)
select new
{
AllocatedPoints = (p.PersonTypeId == (int)PersonType.Old
? defaultOldPersonPoints
: p.PersonTypeId == (int)PersonType.Young
? defaultYoungPersonPoints : 0)
+ (int)(
(p.PersonTypeId == (int)PersonType.Old
? defaultOldPersonPoints
: p.PersonTypeId == (int)PersonType.Young
? defaultYoungPersonPoints : 0)
* (p.ContractedHours.HasValue
? (p.ContractedHours.Value - defaultHours) / defaultHours : 0))
});
// Using the LET allows me to clean up the code somewhat but causes a massive performance hit
var exampleUsingLet =
(from p in people
join op in otherPeople
on p.PersonId equals op.PersonId into inner
from outer in inner.DefaultIfEmpty(null)
let defaultPoints = p.PersonTypeId == (int)PersonType.Old
? defaultOldPersonPoints
: p.PersonTypeId == (int)PersonType.Young
? defaultYoungPersonPoints : 0
let contractedHourRatio = p.ContractedHours.HasValue
? (p.ContractedHours.Value - defaultHours) / defaultHours : 0
select new
{
AllocatedPoints = defaultPoints + (int)(defaultPoints * contractedHourRatio)
});
答案 0 :(得分:3)
如果查询性能是问题所在,请考虑将其移至LINQ-to-Objects。例如,目前,您在投影中没有使用p
以外的任何内容(我不清楚为什么您正在做似乎是左外 - 实际上加入,所以你可以做一些像:
var queryBase = from p in people
join op in otherPeople
on p.PersonId equals op.PersonId into inner
from outer in inner.DefaultIfEmpty(null)
select p;
var query = from p in queryBase.AsEnumerable() // <=== switch to LINQ-to-Objects
let defaultPoints = p.PersonTypeId == (int)PersonType.Old
? defaultOldPersonPoints
: p.PersonTypeId == (int)PersonType.Young
? defaultYoungPersonPoints : 0
let contractedHourRatio = p.ContractedHours.HasValue
? (p.ContractedHours.Value - defaultHours) / defaultHours : 0
select new
{
AllocatedPoints = defaultPoints + (int)(defaultPoints * contractedHourRatio)
});
这里,SQL查询应该非常简单;所有更复杂的工作都是在LINQ-to-Objects中完成的。