NHibernate Query/QueryOver 与日期时间比较

NHibernate Query/QueryOver with DateTime Comparison

我有这个 QueryOver 方法:

public IEnumerable<TrackedReportData> GetUnused(TimeSpan cacheExpiration)
{
    return Session
        .QueryOver<TrackedReportData>()
        .Where(t => t.CacheSize > 0)
        // TODO: NHibernate doesn't support DateTime comparison out-of-box.
        //.Where(t => t.CacheSize > 0 && !t.IsRecentlyAccessed(cacheExpiration))
        .List()
        .Where(t => !t.IsRecentlyAccessed(cacheExpiration));
}

目前,我正在 SQL 之外过滤我的 collection。性能不太好。

我的 IsRecentlyAccessed 方法如下所示:

/// <summary>
/// Returns true if the cacheMeta has been accessed within the last `cacheExpiration`
/// number of milliseconds.
/// </summary>
public bool IsRecentlyAccessed(TimeSpan cacheExpiration)
{
    if (!LastAccessDate.HasValue)
        return false;

    return DateTime.Now.Subtract(LastAccessDate.Value) <= cacheExpiration;
}

NHibernate 不支持 DateTime.Subtract 也不太容易处理 DateTime1 - DateTime2

我浏览了网上的资源,似乎每个人都建议过于复杂 function expressions or 。当我感兴趣的只是减去一个值时,这些解决方案似乎有点矫枉过正。

没有简单的解决办法吗?手工制作 SQL 查询的方法似乎是最好的选择,但遗憾的是 NHibernate 被阻止在其轨道上 一些看似微不足道的东西。

语法不是很好,这需要一些调整,但您应该可以这样做...

return Session
    .QueryOver<TrackedReportData>()
    .Where(t => t.CacheSize > 0)
    .Where(
        Restrictions.Lte(
            Projections.SqlFunction(
                new VarArgsSQLFunction("(", "-", ")"),
                NHibernateUtil.DateTime,
                Projections.Property(t => t.LastAccessDate),
                Projections.Constant(DateTime.Now)),
            cacheExpiration);

下面的呢?

public IEnumerable<TrackedReportData> GetUnused(TimeSpan cacheExpiration)
{
    return Session
        .QueryOver<TrackedReportData>()
        .Where(t => t.CacheSize > 0)
        .Where(Restrictions.Or(
            Restrictions.On<TrackedReportData>(t => t.LastAccessDate).IsNull,
            Restrictions.Where<TrackedReportData>(
                t => t.LastAccessDate < DateTime.Now.Add(-cacheExpiration))))
        .List();
}

NHibernate 知道如何比较日期。那是您的情况不支持的日期计算。将它移动到参数上会导致它在运行时进行评估,而不是尝试将其转换为 SQL.

如果您想将日期计算转换为 SQL,请参阅此 answer to another question