在参数化SQL字符串中使用.Net DateTime的正确方法

时间:2012-04-24 20:00:36

标签: c# .net sql oracle 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格式的方式有关,但我不知道以可靠的方式解决这个问题的正确方法。

4 个答案:

答案 0 :(得分:10)

(根据评论......)

在这种情况下,参数的顺序很重要......尽管你已经给出了它们的名字。我不会想到这一点,这是一个有点破碎的驱动程序的标志,但是将代码更改为:

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

应该修复它。 (顺便说一下,这不一定是构建参数的方式,但这在某种程度上并不重要。)

开始将日期/时间值指定为字符串。 非常糟糕的想法引入比你需要的更多的字符串转换。

答案 1 :(得分: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,因此值应正确转换。

答案 2 :(得分:2)

Oracle期望日期格式为'DD-Mon-YYYY',因此您需要基本格式化日期值并将其分配给参数值。

编辑:我注意到最新版本的ODP似乎更好地处理了日期时间参数。例如,当日期/时间列上的WHERE子句存在约束时,这可以正常工作:

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

使用最新版本的ODP以这种方式运行查询工作正常。但是我有很多代码需要将日期/时间值作为格式化字符串传递,以便Oracle接受它们。

答案 3 :(得分:2)

对于那些可能错过它的人,请参阅{strong> @JonSkeet 下the accepted answer @kprobst 的评论:

如果您尝试使用名称绑定而不在BindByName上设置Command属性,那么格式化参数值等的效果并不重要。

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