2016-04-16 78 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

我還沒有找到任何更好的方法。我已經更新了我的回答。 –