2012-04-24 20 views
6

有幾個關於在Sql語句中使用.Net DateTime的問題,但是他們都沒有解決我的問題。在參數化SQL字符串中使用.Net DateTime的正確方法

我用下面的代碼來查詢Oracle數據庫:

private DataTable QueryByIdAndDate(string id, DateTime fdate, DateTime tdate) { 
    string query = "SELECT * FROM table WHERE ID = :id AND DATE_TIME BETWEEN :from AND :to" 
    DbCommand cmd = db.CreateCommand(); 
    cmd.CommandType = CommandType.Text; 
    cmd.CommandText = query; 

    DbParameter fromDate = CreateDateParameter(cmd, fdate); 
    fromDate.ParameterName = "from"; 
    DbParameter toDate = CreateDateParameter(cmd, tdate); 
    toDate.ParameterName = "to"; 
    DbParameter idParam = CreateStringParameter(cmd, id); 
    idParam.ParameterName = "id"; 

    cmd.Parameters.AddRange(new DbParameter[] { fromDate, toDate, idParam }); 
    return db.ExecuteQuery(cmd); 
} 

private DbParameter CreateDateParameter(DbCommand cmd, DateTime date) { 
    DbParameter param = cmd.CreateParameter(); 
    param.DbType = DbType.DateTime; 
    param.Direction = ParameterDirection.Input; 
    param.Value = date; 
    return param; 
} 

但它不能正常工作。當就試圖像這樣的代碼:

DataTable result = QueryByIdAndDate("12345", DateTime.Now, DateTime.Now.AddDays(1)); 

它提供了以下錯誤: ORA-01847:月日必須在1月的最後一天之間

我假設它做與DateTime格式化的方式,但我不知道以可靠的方式解決這個問題的正確方法。

+0

你會不會恰好在一個月的30號裏跑步,只有30天? – 2012-04-24 20:09:24

+0

沒有。它使用DateTime.Now和DateTime.Now.AddDays(1)顯示的示例失敗。 – user12345613 2012-04-24 20:10:11

+2

您的驅動程序是否絕對支持命名參數?如果它試圖按位置使用它們,它最終會使用「id」值作爲「to」部分,這可能會被破壞。你在使用哪個驅動程序? – 2012-04-24 20:11:07

回答

10

(按評論...)

它看起來像在這種情況下,參數事宜......的順序儘管你已經給了他們名字的事實。我不會期待這一點,這是一個有點破碎的驅動程序的跡象,但將您的代碼更改爲:

cmd.Parameters.AddRange(new DbParameter[] { idParam, fromDate, toDate }); 

應該修復它。 (順便說一句,這不一定是你構造參數的方式,但這在這裏有點不重要。)

不是開始指定日期/時間值作爲字符串。這是一個真的壞主意引入任何更多的字符串轉換比你需要。

+0

是的,我甚至沒有想過這個數組的順序(這是愚蠢的),因爲它們被命名爲參數。另外,對於正確構建參數的任何意見或建議,我都會公開。 – user12345613 2012-04-24 20:21:29

+0

根據我的經驗,有很多東西在oracle.net驅動中被破壞,包括參數順序或需要更改SQL語句以擺脫NULL引用異常。 – 2012-04-24 20:23:19

+0

@ user12345613:我不能說這是一個我有很多經驗的領域,但是如果你使用強類型的命令參數集合,你很可能會得到諸如「AddWithValue」之類的選項,這些選項使生活更輕鬆。 – 2012-04-24 20:23:24

3

DateTime值轉換爲格式化的日期字符串:

private DbParameter CreateDateParameter(DbCommand cmd, DateTime date) 
{ 
    DbParameter param = cmd.CreateParameter(); 
    param.DbType = DbType.DateTime; 
    param.Direction = ParameterDirection.Input; 
    param.Value = date.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); 
    return param; 
} 

即使你發送一個字符串值,將DbType仍設置爲DateTime,所以價值應該得到適當的轉換。

+0

請注意,即使這確實是問題,您可能想要使用不變文化,並且您一定要將「hh」更改爲「 HH」。我強烈建議*反對*自己執行此類轉換。 – 2012-04-24 20:20:06

+0

@JonSkeet沒有任何東西。同意,我直接跳到格式問題,從不考慮參數順序。根據您的建議更新。 – mgnoonan 2012-04-24 20:31:59

2

Oracle期望格式化爲「DD-Mon-YYYY」的日期,因此您需要基本上按照這種方式格式化日期值並將其分配給參數值。

編輯:我注意到最近的ODP版本似乎更好地處理日期時間參數。

DateTime dt = new DateTime(2012, 5, 21); 
cmd.Parameters.Add("some_date_param", dt); 

運行查詢,這種方式與ODP的最新版本正常工作:例如,當有一個WHERE子句在日期/時間列上的約束這工作得很好。但是我有很多代碼需要通過格式化字符串傳遞日期/時間值,以便Oracle能夠接受它們。

1

對於那些可能會錯過它,看到@kprobst註釋接受的答案被@JonSkeet下:

不要緊,你如何格式化參數值等,如果你想使用名稱綁定而不設置Command上的BindByName屬性。

(整個Oracle提供者API是一堆垃圾恕我直言)。

相關問題