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。
我有这个 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。