C# 在参数化SQL字符串中使用.Net DateTime的正确方法
关于在Sql语句中使用.Net DateTime有几个问题,但没有一个解决了我的问题 我正在使用以下代码查询Oracle数据库:C# 在参数化SQL字符串中使用.Net DateTime的正确方法,c#,.net,sql,oracle,datetime,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
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
值转换为格式化的日期字符串:
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
,因此该值应正确转换。Oracle希望日期格式为'DD Mon YYYY',因此您基本上需要以这种方式格式化日期值并将其分配给参数值
编辑:我注意到ODP的最新版本似乎能更好地处理日期时间参数。例如,在日期/时间列上的WHERE子句上有一个约束时,这样做就可以了:
DateTime dt = new DateTime(2012, 5, 21);
cmd.Parameters.Add("some_date_param", dt);
使用最新版本的ODP以这种方式运行查询效果良好。但是我有很多代码,其中日期/时间值需要作为格式化字符串传递,以便Oracle接受它们。(根据注释…)
在这种情况下,参数的顺序很重要。。。尽管你给了他们名字。我没想到会出现这种情况,这是一个有点坏的驱动程序的迹象,但将您的代码更改为:
cmd.Parameters.AddRange(new DbParameter[] { idParam, fromDate, toDate });
你应该把它修好。(顺便说一句,这不一定是构造参数的方式,但这在这里有些无关紧要。)
不要开始将日期/时间值指定为字符串。引入比您需要的更多的字符串转换是一个非常糟糕的主意。对于那些可能错过它的人,请参阅by@JonSkeet下的@kprobst的评论: 如果您试图使用名称绑定而未在
命令
上设置BindByName
属性,则参数值等的格式设置是否良好无关紧要
(整个Oracle provider API都是一堆垃圾)。您不会碰巧在30天内运行它,是吗?不会。使用DateTime.Now和DateTime.Now.AddDays(1)显示的示例失败;您的驱动程序是否确实支持命名参数?如果它试图按位置使用它们,它将使用“id”值作为“to”部分,这可能会被破坏。你在用哪个司机?@JonSkeet哇,你猜对了。我使用的是Oracle.DataAccess,它必须按位置使用它们,因为我在将参数放入数组时更改了参数的顺序,现在它可以工作了。经过一个小时的胡闹,结果真令人讨厌。把这个作为答案,你就赢了,谢谢@user12345613:很高兴看到心理调试经常工作:)请注意,即使这确实是问题所在,您也可能希望使用不变区域性,并且您肯定希望将“hh”更改为“hh”。我强烈建议不要自己进行这种转换。没有任何东西可以通过@JonSkeet。同意,我直接跳到了格式问题,从未考虑过参数顺序。根据您的建议更新。是的,我甚至没有考虑数组的顺序(这很愚蠢),因为它们是命名参数。此外,我愿意听取任何关于正确构造参数的意见或建议。根据我的经验,oracle.net驱动程序中有很多地方是不正确的,包括参数顺序或需要更改SQL语句以消除空引用异常。@user12345613:我不能说这是我有很多经验的领域,但是如果您使用强类型命令参数集合,您可能会得到诸如
AddWithValue
之类的选项,这会使您的生活更轻松。@JonSkeet我必须检查一下。就目前而言,我很高兴这能起作用。ODP.Net中的OracleCommand对象有一个名为BindByName
的属性,当设置为true时,可以消除这个问题。默认情况下,它设置为false,因为以前版本的驱动程序用于按位置绑定。