0

我有一个 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)
     });
4

1 回答 1

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 中完成。

于 2013-06-25T09:21:05.850 回答