NHibernate - Select 按服务器日期记录

NHibernate - Select records by server's date

我正在使用 NHibernate4 和 Oracle 12。 NHibernate 配置为使用 Oracle10gDialect。

第一个相关代码。

public class WorkOrder 
{
    ........
    public virtual DateTime CreationDate {get; set;}
    ........
}

创建日期映射为:

Map(x => x.CreationDate)    
  .Column("CREATION_DATE")
  .CustomType("DateTime")
  .Access.Property()
  .Generated.Never()
  .CustomSqlType("DATE")
  .Not.Nullable();

查询样本:

var workOrders1 = session.Query<WorkOrders>()
       .Where(p => DateTime.Today.Date.Equals(p.CreationDate.Date))
       .ToList();

var workOrders2 = session.Query<WorkOrders>()
       .Where(p => p.CreationDate.Date == DateTime.Today.Date)
       .ToList();

    var workOrders3 = session.Query<WorkOrders>()
       .Where(p => p.CreationDate.Date.Equals(DateTime.Today.Date))
       .ToList();

上面的所有 linq 查询都转换为 sql,如下所示:

select workorders0_.CREATION_DATE  as CREATION11_ 
from   APPS.WORK_ORDERS workorders0_
where  TIMESTAMP '2016-04-16 00:00:00' /* :p0 */ = trunc(workorders0_.CREATION_DATE)

这些查询使用客户端计算机系统时间(并作为参数),而不是服务器系统时间。我总是喜欢使用服务器时间。对于我正在处理的 oracle 数据库,我更喜欢 "sysdate" 因为 "CreationDate" 字段由使用 "sysdate" 函数的插入触发器之前设置。

NHibernate 可以直接使用服务器的日期时间吗?不需要参数。喜欢:

select workorders0_.CREATION_DATE  as CREATION11_
from   APPS.WORK_ORDERS workorders0_
where  trunc(sysdate) = trunc(workorders0_.CREATION_DATE)

总而言之,"where" 部分必须从第一部分更改为第二部分。 NHibernate 版本是 v4.0.30319

where  TIMESTAMP '2016-04-16 00:00:00' /* :p0 */ = trunc(workorders0_.CREATION_DATE)
where  trunc(sysdate) = trunc(workorders0_.CREATION_DATE)

我认为你必须扩展 来支持它。 (甚至 DateTime.Now 也没有翻译成 SQL 等价物。)

如果您的 Oracle sysdate 可以作为函数处理,最简单的方法应该是添加对附加 SQL 函数的支持作为 demonstrated by this blog。 (用SQL服务器,就是sysdatetime(),可以在linq2NH中作为函数处理。)

但不幸的是,当前 存在很大限制:只有对实体或实体属性的方法调用可能会转换为 SQL。任何其他调用都将在 .Net 运行 时进行评估,如 此处.

所述

为了克服这个问题,我们必须在函数调用中添加一些虚拟参数。这是我在 SQL-Server:

中所做的
create function dbo.customGetDate (@dummy sql_variant = null)
returns datetime2 as
begin
    return sysdatetime()
end
using NHibernate.Linq;

...

public static class CustomLinqExtensions
{
    [LinqExtensionMethod("dbo.customGetDate")]
    public static DateTime GetSysDate(this object dummy)
    {
        // No need to implement it in .Net, unless you wish to call it
        // outside IQueryable context too.
        throw new NotImplementedException();
    }
}

然后你就可以写:

var workOrders1 = session.Query<WorkOrders>()
   .Where(p => p.GetSysDate().Date == p.CreationDate.Date)
   .ToList();

如果你想避免在 db 中声明自定义函数,你应该用更难的方式扩展 linq2NH,比如在我的 self-answer here 中添加你自己的 "LinqToHqlGenerator"。但是您仍然必须在某些实体或实体属性上调用您的扩展程序。

这很丑陋,但我找不到更好的方法。