Sum()导致异常,而不是在没有行时返回0

时间:2009-02-23 09:16:24

标签: c# linq-to-sql nullreferenceexception

我有这段代码(好吧,我没有,但类似的东西:p)

    var dogs = Dogs.Select(ø => new Row
    {
            Name = ø.Name,
            WeightOfNiceCats = ø.Owner
              .Cats
              .Where(æ => !æ.Annoying)
              .Sum(æ => æ.Weight),
    });

在这里,我通过所有的狗,并总结所有不讨厌的猫的重量(成为一个不可空的小数)与猫拥有相同的所有者。当然,几乎所有的猫都很烦,所以我得到了这个错误:

  

无法将null值分配给System.Decimal类型的成员,该类型是不可为空的值类型。

使用的字段或外键都不能为空。因此,当Where子句不返回猫时会发生错误。但是我该如何解决这个问题呢?当发生这种情况时,我希望它返回0。在DefaultIfEmpty()子句后尝试Where,但后来我收到此错误:

  

对象引用未设置为对象的实例。

我猜这是可以理解的。我尝试在??之后添加Sum,但由于此错误,它不会编译:

  

运营商'??'不能应用于'decimal'和'decimal'类型的操作数

当然这也是有道理的。那我该怎么办?如果Sum只是在没有任何要求的情况下返回0,那将会很好。或某种SumOrZero语句。制作一个与Linq2SQL一起使用的SumOrZero方法会不会很难?

4 个答案:

答案 0 :(得分:21)

这就是我现在最终的结果:

.Sum(æ => (decimal?) æ.Weight) ?? 0.0M,

这就像一个魅力。

我仍然希望有一个SumOrZero我可以使用,这与常规Sum完全相同,但它不会因任何原因返回null。就像其他人已经注意到的那样,这对于IEnumerable来说非常容易,但是为IQueryable创建它会更加狡猾,所以它可以与Linq2SQL等一起使用。所以我将它留在那里现在。虽然如果某人有一天感到无聊并为SumOrZero写了一个IQueryable,它与Linq2SQL一起用于所有数字类型,请告诉我:D

答案 1 :(得分:5)

在LINQ to Objects中它很容易。使用LINQ to SQL会更难。您可以编写自己的扩展方法,该方法使用从普通表达式构建的表达式调用Queryable.Sum,并使用强制转换为可空类型。我怀疑你需要这样做?但是在调用代码中为0m。换句话说,你可以这样做:

.SumOrNull(æ => æ.Weight) ?? 0M,

.SumOrNull的签名为:

public static decimal? SumOrNull<TSource, decimal>(this IQueryable<TSource>,
    Func<TSource,decimal> projection)

你基本上可以为Queryable支持的所有值类型编写。你可以一般地写它,并使用反射在Queryable中调用适当的方法,但这也会很蹩脚。

说实话,我觉得你最擅长的是你。

答案 2 :(得分:3)

你已经给出的技巧(.Sum(æ => (decimal?) æ.Weight) ?? 0.0M)是关于这个场景在数据库中作为查询执行时所能想到的最好的技巧。有点烦人,但还有更糟糕的事情......

与LINQ-to-Objects不同,您不能只添加自己的扩展方法,因为它需要由底层提供程序映射。

答案 3 :(得分:0)

你想使用DefaultIfEmpty,它将返回一个单元素为0的IEnumberable,并且在语义上与你需要的相同。

由于你有一个可以为空的十进制数,你可能不得不使用方法的第二个版本来获取2个参数。