2016-04-16 77 views
1

使用NHibernate4和Oracle 12进行操作。 NHibernate配置为使用Oracle10gDialect。NHibernate - 根据服务器日期选择记录

第一个相关的代码。

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

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

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

作为总结,“其中”部分必须从第一个改为第二个。 NHibernate的版本是v4.0.30319

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

回答

2

我认为你必须延长支持这一点。 (即使DateTime.Now没有被翻译到某些SQL当量。)

最简单的方法应该增加额外的SQL函数支持,demonstrated by this blog,如果你的Oracle sysdate可以作为一个函数来处理。 (使用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(); 

如果你想避免分贝声明的自定义功能,你应该用更难的方法扩展linq2NH,比如像我的self-answer here中那样添加你自己的“LinqToHqlGenerator”。但是您仍然需要在某个实体或实体属性上调用您的扩展。

这是丑陋的,但我没有找到任何更好的方法。

+0

谢谢你很多。但我得到NHibernate.dll中发生类型'System.NotSupportedException'的未处理的异常 其他信息:PartialEvalException(NotImplementedException(“该方法或操作未实现。“),PartialEvalException(NotImplementedException(”该方法或操作没有实现。“),GetSysDate())。Date) 我搜索了这个方法,它必须工作,我做了一些测试,不同的oracledialects什么都没有改变 – ayocak

+0

现在做我自己的测试,是的,它看起来这个扩展属性不支持参数较少的功能......很不幸,我可以调用任何具有参数的函数,包括用户定义的函数(包括他们的名字中的模式)。通过添加一个具有虚拟参数的用户定义的函数来调用参数较少的函数,但我仍然在寻找更好的解决方案,看起来它必须在某个映射的实体属性上调用,相当大的一个限制 –

+0

我还没有找到任何更好的方法。我已经更新了我的回答。 –