Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NHibernate Query/QueryOver with DateTime Comparison

I have this QueryOver method:

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));
}

Currently, I am filtering my collection outside of SQL. Not so good for performance.

My IsRecentlyAccessed method looks like:

/// <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 does not support DateTime.Subtract nor does it handle DateTime1 - DateTime2 very easily.

I've looked through resources online and everyone seems to be suggesting overly complex function expressions or extension methods. These solutions seem overkill when all I'm interested in doing is subtracting a value.

Are there no simple solutions? A manual approach to crafting the SQL query seems to be one's best bet, but it's a shame NHibernate is stopped in its tracks by something which appears to be trivial.

like image 968
Sean Anderson Avatar asked Feb 28 '26 09:02

Sean Anderson


1 Answers

What about the following?

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 knows how to compare dates. That is the date computation which is not supported in your case. Moving it on the parameter caused it to be evaluated at runtime instead of trying to translate it to SQL.

If you want to have date computations translated to SQL, see this answer to another question.

like image 186
Frédéric Avatar answered Mar 02 '26 21:03

Frédéric



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!