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)
我认为你必须扩展 linq-to-nhibernate 来支持它。 (甚至 DateTime.Now
也没有翻译成 SQL 等价物。)
如果您的 Oracle sysdate
可以作为函数处理,最简单的方法应该是添加对附加 SQL 函数的支持作为 demonstrated by this blog。 (用SQL服务器,就是sysdatetime()
,可以在linq2NH中作为函数处理。)
但不幸的是,当前 linq-to-nhibernate 存在很大限制:只有对实体或实体属性的方法调用可能会转换为 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"。但是您仍然必须在某些实体或实体属性上调用您的扩展程序。
这很丑陋,但我找不到更好的方法。
我正在使用 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)
我认为你必须扩展 linq-to-nhibernate 来支持它。 (甚至 DateTime.Now
也没有翻译成 SQL 等价物。)
如果您的 Oracle sysdate
可以作为函数处理,最简单的方法应该是添加对附加 SQL 函数的支持作为 demonstrated by this blog。 (用SQL服务器,就是sysdatetime()
,可以在linq2NH中作为函数处理。)
但不幸的是,当前 linq-to-nhibernate 存在很大限制:只有对实体或实体属性的方法调用可能会转换为 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"。但是您仍然必须在某些实体或实体属性上调用您的扩展程序。
这很丑陋,但我找不到更好的方法。