使用LINQ Average()方法处理null结果

时间:2009-08-17 10:07:37

标签: c# .net linq

我是LINQ的新手,正在尝试从表格到图表创建一些数据点。此表中的三个重要字段是id,时间和值。我正在编写一个查询来获取所选id的设定时间内的平均值。我写的LINQ如下:

var value = (from t in _table
             where t.Id == id
                 && t.Time >= intervalStartTime
                 && t.Time <= intervalEndTime
             select t.Value).Average();

然而,这在运行时崩溃:

  

“无法分配空值   System.Decimal类型的成员   这是一个不可为空的值类型。“

在某些时间间隔没有数据,因此SQL LINQ生成返回null,我希望将COALESCED设置为0,而是使应用程序崩溃。有没有办法编写这个LINQ查询以便能够正确处理这个问题?

使表格更清晰的表定义:

[Serializable]
[Table(Name = "ExampleTable")]
public class ExampleTable
{
    [Column(Name = "Id")]
    public int Id { get; set; }

    [Column(Name = "Time")]
    public DateTime Time { get; set; }

    [Column(Name = "Value")]
    public int Value{ get; set; }
}

5 个答案:

答案 0 :(得分:20)

我想你想要

var value = (from t in _table
             where t.Id == id
                && t.Time >= intervalStartTime
                && t.Time <= intervalEndTime
             select (int?)t.Value).Average()

通过这种方式,您获得了double?,但如果没有(int?)广告,您需要返回double,而不能null

这是因为签名

double Enumerable.Average(IEnumerable<int> source)
double? Enumerable.Average(IEnumerable<int?> source)

现在,要获得平均值0而不是null,您需要将合并运算符放在最后

var value = (from t in _table
             where t.Id == id
                && t.Time >= intervalStartTime
                && t.Time <= intervalEndTime
             select (int?)t.Value).Average() ?? 0.0;

恕我直言,这是Enumerable / Queryable类的一个非常糟糕的设计;为什么不能Average(IEnumerable<int>)返回double?,为什么只能Average(IEnumerable<int?>)

答案 1 :(得分:16)

编辑:完成更改:)

好的,这个怎么样:

var value = (from t in _table
             where t.Id == id
                 && t.Time >= intervalStartTime
                 && t.Time <= intervalEndTime
             select t.Value).DefaultIfEmpty().Average()

我相信逻辑上你想要的东西 - 将{}改为{0},这样可以实现所有平均值。我不知道它是否会在SQL方面做你想做的事。

答案 2 :(得分:1)

编辑:总返工

尝试将值转换为可以为空的

var value = (from t in _table
         where t.Id == id
             && t.Time >= intervalStartTime
             && t.Time <= intervalEndTime
         select ((int?)t.Value) ?? 0).Average()

答案 3 :(得分:0)

尝试以下方法。它将简单地跳过查询返回的所有空项。

var value = (from t in _table
             where t != null
             where t.Id == id
                 && t.Time >= intervalStartTime
                 && t.Time <= intervalEndTime
             select t.Value).Average();

如果要将空项明确地视为零,那么简单地使用条件运算符就可以完成这项任务:

var value = (from t in _table
             where t == null ||
                 (t.Id == id
                 && t.Time >= intervalStartTime
                 && t.Time <= intervalEndTime)
             select t == null ? 0 : t.Value).Average();

答案 4 :(得分:0)

你可以在初始查询中使用temp吗?

E.g:

var temp = (from t in _table
            where t.Id == id
                && t.Time >= intervalStartTime
                && t.Time <= intervalEndTime
            select t.Value) ??  new List<int>() {0};
var value = temp.Average();

不确定这是否有帮助。