NHibernate - 按服务器的日期选择记录

时间:2016-04-16 19:41:18

标签: c# nhibernate linq-to-nhibernate

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

第一个相关代码。

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

CreationDate映射为:

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数据库,我更喜欢&#34; sysdate&#34;因为&#34; CreationDate&#34;在使用&#34; sysdate&#34;插入触发器之前设置的字段功能。

NHibernate可以直接使用服务器的日期时间吗?和参数不是必需的。像:

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

总结,&#34;其中&#34;部分必须从第一个更改为第二个。 NHibernate版本是v4.0.30319

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

1 个答案:

答案 0 :(得分:2)

我认为你必须延长来支持这一点。 (即使DateTime.Now也没有转换为某种SQL等价物。)

如果您的Oracle sysdate可以作为函数处理,最简单的方法应该是添加对demonstrated by this blog的其他SQL函数的支持。 (对于SQL Server,它是sysdatetime(),它可以作为函数在linq2NH中处理。)

但遗憾的是,当前存在很大的局限性:对实体或实体属性的唯一方法调用可能会被转换为SQL。任何其他调用将在.Net运行时进行评估,如here所述。

为了解决这个问题,我们必须在函数调用中添加一些伪参数。这是我在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,比如添加你自己的&#34; LinqToHqlGenerator&#34;和我的self-answer here一样。但是您仍然需要在某个实体或实体属性上调用您的扩展名。

这很难看,但我找不到更好的方法。