如果 NodaTime 使用 Duration 而 Postgres 使用 INTERVAL/Period,如何在 EF Core 中进行时间戳运算?

How to do timestamp arithmetic in EF Core if NodaTime uses Duration and Postgres uses INTERVAL/Period?

在我的 .NET Core 3.1 项目中,我目前正在将与时间相关的代码移动到 NodaTime。

我在翻译某些查询时遇到问题,因为在 NodaTime 中两个 Instant 之间的差异产生一个 Duration,而在 Postgres 中两个 TIMESTAMP 之间的差异产生一个 INTERVAL。

Npgsql 将 Instant 映射到 TIMESTAMP,但 INTERVAL 是 Period。

假设我有一个名为“访问”的实体,它有一个 ID 和两次:“到达”和“离开”。 (这不是我的实际用例,我有几个实体有这个问题,所以这是一个最小的例子)

public class Visit
{
    public int Id { get; set; }
    public Instant Arrived { get; set; }
    public Instant Left { get; set; }
}

现在我想查找访客停留时间少于给定时间的访问:

public async Task<List<Visit>> FindVisitsShorterThan(DbSet<Visit> dbSet, Duration duration)
{
    var visits =
        from visit in dbSet
        where (visit.Left - visit.Arrived) < duration
        select visit;
    return await visits.ToListAsync();
}

如果我这样做,Npgsql 会抱怨 System.InvalidCastException: Can't write CLR type NodaTime.Duration with handler type TimestampHandler - 因为不支持持续时间。

另一方面,如果我将 Duration 转换为 Period,NodaTime 会抱怨,因为从它的角度来看,该差异是 Duration,无法与 < 与 Period 进行比较。

我可以做几件事,但 none 看起来很理想:

有没有更好的方法?

这确实是当前 Npgsql EF 对 NodaTime 类型支持的不幸限制。

好消息是我刚刚实现了上面的内容,以及其他一些 NodaTime 算术翻译 - see this tracking issue。这将包含在下周即将发布的 EF Core 5.0 中 - 只需等待几天,一切都会好起来的。