2

我正在开发一个程序,该程序从访问数据库中提取字符串字段,将名称(名字和姓氏)与日期分开,然后将名称与日期分开保存在不同的访问数据库中。

除了某些日期值为空之外,我已经完成了所有工作,因此我需要对 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();
}
4

5 回答 5

6

像下面这样的东西应该是你想要的:

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 包含两个问号的原因——它们只是占位符。

于 2012-07-17T22:36:45.907 回答
4

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

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

?? 是空合并运算符

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

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

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

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

于 2012-07-17T22:32:22.480 回答
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(); 
} 

顺便说一句,插入语句通常由ExecuteNonQuery

于 2012-07-17T22:37:19.213 回答
0

使用DBNull.Value

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

附带说明一下,使用OleDbParameterCollection.AddWithValue 会自动推断数据类型并允许您缩短代码:

SQLCommand.Parameters.AddWithValue("@QADATE", DBNull.Value);
于 2012-07-17T22:33:26.633 回答
0

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

于 2012-07-17T22:35:30.220 回答