我正在使用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)
答案 0 :(得分:2)
我认为你必须延长linq-to-nhibernate来支持这一点。 (即使DateTime.Now
也没有转换为某种SQL等价物。)
如果您的Oracle sysdate
可以作为函数处理,最简单的方法应该是添加对demonstrated by this blog的其他SQL函数的支持。 (对于SQL Server,它是sysdatetime()
,它可以作为函数在linq2NH中处理。)
但遗憾的是,当前linq-to-nhibernate存在很大的局限性:对实体或实体属性的唯一方法调用可能会被转换为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一样。但是您仍然需要在某个实体或实体属性上调用您的扩展名。
这很难看,但我找不到更好的方法。