参数化查询和NULL DateTime值

时间:2012-07-17 22:28:30

标签: c# sql ms-access ms-access-2007

我正在使用一个从访问数据库中提取字符串字段的程序,从日期中分离出一个名称(第一个和最后一个),然后将该名称与另一个访问数据库中的日期分开保存。

我已经完成了所有工作,除了一些日期值为null所以我需要参数化SQL,但我还没弄清楚如何使参数化工作。

我为变量添加了虚拟值,并将它们添加到表中就好了。我已经删除了下面代码片段中的其他变量,因为它们都是重复的。 os是一个包含结构数据的列表。

string sqlcmd = "INSERT INTO signatures VALUES ('" + os.QASignature + "', 'QADate = @QADATE'";
System.Data.OleDb.OleDbCommand SQLCommand = new System.Data.OleDb.OleDbCommand(sqlcmd, Connection);
using (SQLCommand)
{
    SQLCommand.Parameters.Add("@QADATE", System.Data.OleDb.OleDbType.Date).Value = os.QADate;
    SQLDataReader = SQLCommand.ExecuteReader();
}

5 个答案:

答案 0 :(得分:4)

您需要将null“转换”为DBNull.Value。实现这一点的一种方法,假设QADate是可以为空的DateTime(所以DateTime?)可能是:

... .Value = os.QADate ?? DBNull.Value;

??是null-coalescing operator

编辑:您可能实际需要强制转换以确保两个操作数的类型相同:

... .Value = (object)os.QADate ?? DBNull.Value;

另外,为什么不使用QASignature的参数?你为什么“内联”这个价值?我不知道QASignature会包含什么,但这使您容易受到SQL Injection的攻击。<​​/ p>

最后,为什么要使用ExecuteReader()进行插入?为什么不使用ExecuteNonQuery()

答案 1 :(得分:4)

以下内容应该是您想要的:

string sqlcmd = "INSERT INTO signatures (QASignature, QADate) VALUES (?, ?)";
using (System.Data.OleDb.OleDbCommand SQLCommand = new System.Data.OleDb.OleDbCommand(sqlcmd, Connection))
{
    SQLCommand.Parameters.Add(new OleDbParameter() { Name = "QASignature", Value = os.QASignature, DbType = DbType.String});
    SQLCommand.Parameters.Add(new OleDbParameter() { Name = "QADATE", Value = os.QADate, DbType = DbType.DateTime});
    SQLCommand.ExecuteNonQuery(); //Use ExecuteReader or ExecuteScalar when you want to return something
} 

如果os.QADate可以为空(DateTime?System.Nullable<DateTime>),那么您将执行以下操作:

if(os.QADate == null) //Could easily be os.QADate == DateTime.MinValue too, for example
{
    SQLCommand.Parameters.Add(new OleDbParameter() { Name = "@QADATE", Value = DBNull.Value, DbType = DbType.DateTime});
}
else{
    SQLCommand.Parameters.Add(new OleDbParameter() { Name = "@QADATE", Value = os.QADate, DbType = DbType.DateTime});
}

请注意,您不应该像原始示例中那样混合字符串连接和参数 - 它是一个或另一个!实际上,它应该只是参数化以防止SQL注入,并获得其他好处(比如更容易键入,在某些RDBMS中,参数化查询的性能更好)。

另请注意,OleDBCommand不会从命名参数中受益 - 参数必须按照它们在SQL中出现的顺序添加到查询中。这就是SQL Query包含两个问号的原因 - 它们只是占位符。

答案 2 :(得分:1)

DateTime不能为null,如果未初始化该值,则为DateTime.MinValue。 您需要测试这种情况并将参数也用于字符串值。

using System.Data.OleDb;
....

string sqlcmd = "INSERT INTO signatures VALUES (@QASignature, @QADATE)"; 
using(OleDbCommand SQLCommand = new OleDbCommand(sqlcmd, Connection))
{ 
    SQLCommand.Parameters.AddWithValue("@QASignature",  os.QASignature);
    SQLCommand.Parameters.Add("@QADATE", OleDbType.Date).Value = 
               (os.QADate == DateTime.MinValue 
               ? (object)DBNull.Value
               : (object)os.QADate); 
    SQLDataReader = SQLCommand.ExecuteNonQuery(); 
} 

顺便说一句,insert语句通常由ExecuteNonQuery

执行

答案 3 :(得分:0)

使用DBNull.Value

SQLCommand.Parameters.Add("@QADATE", 
                          System.Data.OleDb.OleDbType.Date).Value = DBNull.Value;

作为旁注,使用OleDbParameterCollection.AddWithValue会自动推断数据类型并允许您缩短代码:

SQLCommand.Parameters.AddWithValue("@QADATE", DBNull.Value);

答案 4 :(得分:0)

考虑使用Nullable(of T)结构。然后,只有在源对象中实际存在变量时才能设置它。否则,该值将设置为Null并将其自身很好地传递给SQL参数。许多旧的TableAdapter类和较新的EntityFramework对象也使用Nullable(of T)结构。