计算项目并按级别对其进行分组

时间:2014-09-01 11:57:40

标签: c# entity-framework linq-to-entities

我正在使用Entity Framework 6,我有以下Linq查询:

  IDictionary<BodyMassIndexLevel, Int32> bmistats = 
    context.Evaluations

    // Get all evaluations where Height and Weight measures were done
    .Where(x => x.Height != null && x.Weight != null)

    // Select the date of the evaluation, the worker id and calculate BMI
    .Select(x => new { Date = x.Date, Worker = x.Worker.Id, BMI = x.Weight.Value / Math.Pow(x.Height.Value / 100, 2) })

    // Group by worker
    .GroupBy(x => x.Worker)

    // Get the most recent evaluation for each worker and so the most recent BMI
    .Select(x => x.OrderByDescending(y => y.Date).Select(y => new { BMI = y.BMI }).FirstOrDefault())

    // Cache the result in memory
    .ToList()

    // Count the number of BMIS in each level
    .With(z =>
      new Dictionary<BodyMassIndexLevel, Int32> {
        { BodyMassIndexLevel.SevereThinness, z.Count(w => w.BMI < 16) },
        { BodyMassIndexLevel.MildThinness, z.Count(w => w.BMI >= 16 && w.BMI < 17) },
        { BodyMassIndexLevel.ModerateThinness, z.Count(w => w.BMI >= 17 && w.BMI < 18.5) },
        { BodyMassIndexLevel.Normal, z.Count(w => w.BMI >= 18.5 && w.BMI < 25) },
        { BodyMassIndexLevel.PreObese, z.Count(w => w.BMI >= 25 && w.BMI < 30) },
        { BodyMassIndexLevel.ObeseClassI, z.Count(w => w.BMI >= 30 && w.BMI < 35) },
        { BodyMassIndexLevel.ObeseClassII, z.Count(w => w.BMI >= 35 && w.BMI < 40) },
        { BodyMassIndexLevel.ObeseClassIII, z.Count(w => w.BMI >= 40) }
      }
    );

我有两个问题:

  1. 是否可以提高此查询的效果?

  2. 我可以将计数部分的级别移动到查询中,因此没有ToList()吗?

1 个答案:

答案 0 :(得分:0)

例如

  1. 之后为BMI制作类似Truncate的内容 //选择评估日期,工人ID并计算BMI
  2. 使用(BMILevelName | BMIValues)列创建 BMILevel 表,其中包含(BodyMassIndexLevel.ModerateThinness,17),(BodyMassIndexLevel.PreObese,25)等行,( BodyMassIndexLevel.PreObese,26)等
  3. JOIN your select query with *BMILevel* table on query.BMI = BMILevel.BMIValue,而不是GroupBy BMILevel.BMILevelName,最后是Count所有群组。
  4. 或者,您可以使用包含(BodyMassIndexLevel.ModerateThinness,17,18),(BodyMassIndexLevel)等行的列(BMILevelName | BMIValueBeginInterval,BMIValueEndInterval)定义 BMILevel 。 PreObese,25,30)

    然后执行

    query JOIN BMILevel ON query.BMI BETWEEN BMILevel.BMIValueBeginInterval AND BMILevel.BMIValueEndInterval
    

    我认为EF可以改变&#39;&#39;&#39;&amp;&amp;&#39;&#39;&gt;&#39;在.Where()(或加入)中正确调用


    <强>更新

    如果您不想创建另一个表,您可以尝试创建样本类型对象的内存中列表

    class BMILevel {
       public BMILevelEnum BMILevelName {get;set;}
       public double BMILevelValueBeginInterval {get;set;}
       public double BMILevelValueEndInterval {get;set;}
    }
    

    而不是创建内存中的集合:

    var bmiLevels = new List<BMILevel> { new BMILevel {...}, ... }
    

    以我上面描述的方式使用它。 我不知道EF 6有多好,但旧版本无法处理非实体操作(它无法将表达式转换为正确的SQL),因此导致查询效率低下或错误。

    更快地执行查询的唯一方法是将其委派给SQL Server。您可以使用EF功能,因此可能需要创建新表。另一种方法 - 使用ADO.NET(SqlCommand,SqlConnection等)并绕过EF。