`EF.Functions.Sum` over `TimeSpan`/`Duration`/`Period`: a filter on the group becomes `<> NULL`, and null checks on the result fold away
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
- #4102 của @CaffeinatedCoder — đã đóng, không merge
Đánh giá
- Độ khó
- 3/5
- Thời gian dự kiến
- 1-2 ngày
- Mức phù hợp với người mới
- 35/100
Hướng nghiên cứu
Read src/EFCore.PG/Query/Internal/NpgsqlSqlNullabilityProcessor.cs lines 418-430 where SUM over interval skips null-semantics. Visit the wrapped expression's components like the code below does and report it nullable. Add a test using the issue's GroupBy/Sum repro to verify the FILTER becomes IS NOT NULL.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
| Environment | |
|---|---|
| PostgreSQL | 18.6 (postgres:18), session TimeZone Etc/UTC |
| .NET 10 | runtime 10.0.11, Npgsql.EntityFrameworkCore.PostgreSQL(.NodaTime) 10.0.3, EF Core 10.0.4 |
| .NET 11 | runtime 11.0.0-rc.2, Npgsql.EntityFrameworkCore.PostgreSQL(.NodaTime) 11.0.0-rc.2, EF Core 11.0.0-rc.2 |
| Also | Npgsql 10.0.3 on both lines, NodaTime 3.2.2, macOS arm64 |
Both lines print the same output. main at 150011d has the same code.
context.Rows.GroupBy(r => r.Group).Select(g => new { g.Key, Sum = EF.Functions.Sum(g.Where(r => r.Duration != null).Select(r => r.Duration!.Value)) })
SELECT r."Group" AS "Key", sum(r."Duration") FILTER (WHERE r."Duration" <> NULL) AS "Sum"
<> NULL is never true, so the sum is NULL for every group. A Where(x => x.Sum == null) on top then becomes HAVING FALSE and returns nothing. TimeSpan behaves the same way. EF.Functions.Average is correct: FILTER (WHERE ... IS NOT NULL).
Repro
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using NodaTime;
await using var context = new TestContext();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
context.Rows.AddRange(
new Row { Group = 1, Duration = Duration.FromHours(1), Span = TimeSpan.FromHours(1) },
new Row { Group = 1, Duration = null, Span = null },
new Row { Group = 1, Duration = Duration.FromHours(2), Span = TimeSpan.FromHours(2) });
await context.SaveChangesAsync();
var durations = context.Rows.GroupBy(r => r.Group).Select(g => new { g.Key, Sum = EF.Functions.Sum(g.Where(r => r.Duration != null).Select(r => r.Duration!.Value)) });
Console.WriteLine($"Sum of non-null Durations: {(await durations.SingleAsync()).Sum?.ToString() ?? "NULL"} (.NET: 3 hours)");
Console.WriteLine($"... Where(Sum == null).Count(): {await durations.CountAsync(x => x.Sum == null)}");
var spans = context.Rows.GroupBy(r => r.Group).Select(g => new { g.Key, Sum = EF.Functions.Sum(g.Where(r => r.Span != null).Select(r => r.Span!.Value)) });
Console.WriteLine($"Sum of non-null TimeSpans: {(await spans.SingleAsync()).Sum?.ToString() ?? "NULL"} (.NET: 03:00:00)");
public class TestContext : DbContext
{
public DbSet<Row> Rows => Set<Row>();
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseNpgsql(Environment.GetEnvironmentVariable("Test__Npgsql__DefaultConnection"), o => o.UseNodaTime())
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging();
}
public class Row
{
public int Id { get; set; }
public int Group { get; set; }
public Duration? Duration { get; set; }
public TimeSpan? Span { get; set; }
}
Output, the same on both lines:
Sum of non-null Durations: NULL (.NET: 3 hours)
... Where(Sum == null).Count(): 0
Sum of non-null TimeSpans: NULL (.NET: 03:00:00)
The cause is the workaround in NpgsqlSqlNullabilityProcessor.cs#L418-L430. For SUM over an interval it returns the wrapped PgFunctionExpression as is, so:
- its FILTER predicate never goes through null-semantics processing, and
nullablestaysfalsefrom theCOALESCEthat base EF added, although the comment above it says the function returns a nullable value.
Visiting the wrapped expression's components (as the code below it does for the other types) and reporting it as nullable would fix both.
- Ngôn ngữ chính
- C#
- Star
- 1.8k
- Fork
- 268
- Merge trung bình
- 2 giờ 35 phút
- Pull request đã merge (30 ngày)
- 136
Chuẩn bị môi trường
Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của npgsql/efcore.pg
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
Maintainer thường phản hồi trong vòng 1 ngày
-
NTS: the M ordinate is dropped from geometry SQL literals and from geometries stored in JSONCó thể đã có người làm @Ahmed7991 đã nhận 5 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100
npgsql/efcore.pg#4093 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
`TimeSpan`/`Duration` component members: negative values are floored, and intervals computed in SQL are read field by fieldCó thể đã có người làm @jeremy-morren đã nhận 11 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Numeric storage parameters are formatted with the current culture, so migrations emit 0,01 instead of 0.01Có thể đã có người làm @Sorbitol đã nhận 12 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 30/100
Maintainer thường phản hồi trong vòng 1 ngày
-
`Contains` on a JSON primitive collection compares JSON text, so `DateTime` and `TimeOnly` items never matchCó thể đã có người làm @Mr444-dev đã nhận 7 ngày trước. Đang mở
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 45/100
npgsql/efcore.pg#4099 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của npgsql/efcore.pg
Issue tương tự
-
Issue-Bug Needs-Triage
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
Maintainer thường phản hồi trong vòng 2 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 66/100
JiaFeiMiao-K-Cat/DiscImageStudio#281 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
area/access-management Frontend onboarding candidate :handshake:
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
Altinn/altinn-auth#4941 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
aws/aws-sdk-net#4586 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
Kryptos-FR/MarkView.Avalonia#269 · 1 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày