Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 强制求和方法在EF Core中适用时返回NULL_C#_Sql Server_Ef Core 2.2 - Fatal编程技术网

C# 强制求和方法在EF Core中适用时返回NULL

C# 强制求和方法在EF Core中适用时返回NULL,c#,sql-server,ef-core-2.2,C#,Sql Server,Ef Core 2.2,我正在执行一个查询,在该查询中,我偶尔会预期空值,如下所示: .Where(d => d.Id == varid && d.Date >= vardate1 && d.Date <= vardate2) .Sum(d => (decimal?)d.Delta); public static partial class EfCoreExtensions { public static decimal? SumOrDefault<

我正在执行一个查询,在该查询中,我偶尔会预期空值,如下所示:

.Where(d => d.Id == varid && d.Date >= vardate1 && d.Date <= vardate2)
.Sum(d => (decimal?)d.Delta);
public static partial class EfCoreExtensions
{
    public static decimal? SumOrDefault<T>(this IQueryable<T> source, Expression<Func<T, decimal?>> selector)
        => source.GroupBy(e => 0, selector).Select(g => g.Sum()).AsEnumerable().FirstOrDefault();
}
,其中(d=>d.Id==varid&&d.Date>=vardate1&&d.Date(十进制?)d.Delta);
Delta是不可为空的十进制数,intellisense显示总和的结果将是十进制数?因为我介绍了演员。生成的SQL与预期一样,当手动运行时,如果没有匹配的记录,它将正确返回NULL。但是,物化查询的结果始终为0。此行为与非核心EF不同,后者将返回null。这真的是新的预期行为吗?如果是这样的话,我如何在需要时强制它返回null?Null和0在此上下文中具有不同的含义


我可以先输入记录,然后在服务器上求和,但如果EF core能自己做到我所期望的,那就太好了。

很可能是一个bug,但知道EF core designer对不可为空的
Max
/
Min
/
平均值
第一次
/
单次
翻译的设想,如果他们故意这样做是为了模拟(奇怪的)LINQ to Objects nullable
Sum
行为,该行为返回
0
事件,尽管方法的结果类型是nullable

下面的代码片段可以看到它

decimal? result = Enumerable.Empty<decimal?>().Sum(); // result is 0
替换

.Sum(d => (decimal?)d.Delta);

只需确保仅在最终调用时使用它,因为如果在查询表达式树中使用它,作为任何自定义方法,它都不会被识别,并将导致客户端计算或运行时异常。

上述“按常量分组技巧”在EF Core 5.0中不起作用

使用聚合函数的扩展方法的变体可以实现期望的结果。 因此,要使所有空值都返回Null,否则将返回非Null值之和:

    public static decimal? SumOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, decimal?> selector)
        => (from s in source select selector(s))
           .Aggregate((decimal?)null, (acc, item) => acc.HasValue ? acc + item.GetValueOrDefault() : item);
公共静态十进制?SumOrDefault(此IEnumerable源,Func选择器)
=>(从源选择选择器中的)
.Aggregate((十进制?)null,(acc,item)=>acc.HasValue?acc+item.getValuerDefault():item);
或者,如果您希望任何空值都会导致返回空值

    public static decimal? SumAllOrNull<TSource>(this IEnumerable<TSource> source, Func<TSource, decimal?> selector)
        => (from s in source select selector(s))
           .Aggregate((decimal?)null, (acc, item) => acc.HasValue ? acc + item : item.HasValue ? item : null);
公共静态十进制?SumAllOrNull(此IEnumerable源,Func选择器)
=>(从源选择选择器中的)
.Aggregate((十进制?)null,(acc,item)=>acc.HasValue?acc+item:item.HasValue?item:null);
但请注意,如前所述,这只适用于LINQtoObject,而不适用于LINQtoSQL,因此您需要预先使用ToList()或AsEnumerable(),因此它会从数据库中带回您可能想要或需要的更多数据

.Where(d => d.Id == varid && d.Date >= vardate1 && d.Date <= vardate2)
.AsEnumerable()
.SumOrDefault(d => d.Delta);
,其中(d=>d.Id==varid&&d.Date>=vardate1&&d.dated.Delta);

这需要对内存中而不是数据库中的对象进行求和,这可能意味着从数据库返回更多数据。我认为,当SQL返回NULL时,EF决定将其转换为零,而我们无论如何都无法控制要返回的内容。此外,无论在EF Core 5.0上如何,它似乎都不起作用
.Where(d => d.Id == varid && d.Date >= vardate1 && d.Date <= vardate2)
.AsEnumerable()
.SumOrDefault(d => d.Delta);