C# 参数化查询和空DateTime值
我正在使用一个程序,从access数据库中提取一个字符串字段,从日期中分离出一个名称(第一个和最后一个),然后将该名称与另一个access数据库中的日期分开保存 我已经完成了所有的工作,除了一些日期值为空,所以我需要对SQL进行参数化,但我还没有弄清楚如何使参数化工作 我已经为变量输入了虚拟值,它将它们添加到表中。我在下面的代码片段中删去了其他变量,因为它们都是重复的。os是一个保存结构中数据的列表C# 参数化查询和空DateTime值,c#,sql,ms-access,ms-access-2007,C#,Sql,Ms Access,Ms Access 2007,我正在使用一个程序,从access数据库中提取一个字符串字段,从日期中分离出一个名称(第一个和最后一个),然后将该名称与另一个access数据库中的日期分开保存 我已经完成了所有的工作,除了一些日期值为空,所以我需要对SQL进行参数化,但我还没有弄清楚如何使参数化工作 我已经为变量输入了虚拟值,它将它们添加到表中。我在下面的代码片段中删去了其他变量,因为它们都是重复的。os是一个保存结构中数据的列表 string sqlcmd = "INSERT INTO signatures VALUES (
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();
}
您需要将null
转换为。实现这一点的一种方法是,假设QADate是一个可为空的DateTime(那么DateTime?),可以是:
... .Value = os.QADate ?? DBNull.Value;
???是的
编辑:您可能实际上需要强制转换以确保两个操作数的类型相同:
... .Value = (object)os.QADate ?? DBNull.Value;
还有,为什么不为QASignature使用参数??为什么要“内联”这个值?我不知道QASignature会包含什么,但这会让你容易受到攻击
最后,为什么要使用插入?为什么不使用?您需要将null
转换为。实现这一点的一种方法是,假设QADate是一个可为空的DateTime(那么DateTime?),可以是:
... .Value = os.QADate ?? DBNull.Value;
???是的
编辑:您可能实际上需要强制转换以确保两个操作数的类型相同:
... .Value = (object)os.QADate ?? DBNull.Value;
还有,为什么不为QASignature使用参数??为什么要“内联”这个值?我不知道QASignature会包含什么,但这会让你容易受到攻击
最后,为什么要使用插入?为什么不使用?使用:
作为旁注,使用会自动推断数据类型,并允许您缩短代码:
SQLCommand.Parameters.AddWithValue("@QADATE", DBNull.Value);
使用:
作为旁注,使用会自动推断数据类型,并允许您缩短代码:
SQLCommand.Parameters.AddWithValue("@QADATE", DBNull.Value);
考虑使用该结构。然后,只有在源对象中确实存在变量时,才可以设置它。否则,该值将设置为Null,并将其自身很好地传递到SQL参数中。许多旧的TableAdapter类和更新的EntityFramework对象也可以使用Nullable(of T)结构。考虑使用该结构。然后,只有在源对象中确实存在变量时,才可以设置它。否则,该值将设置为Null,并将其自身很好地传递到SQL参数中。许多旧的TableAdapter类和较新的EntityFramework对象也可以使用Nullable(of T)结构。下面的内容应该是您想要的:
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
),则您将执行以下操作:
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查询包含两个问号的原因-它们只是占位符。下面的内容应该是您想要的:
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
),则您将执行以下操作:
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查询包含两个问号的原因-它们只是占位符。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
执行。DateTime不能为空,如果该值未初始化,则为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
DateTime
执行,实际上不能为空,DateTime?
但是,can:-)我假设后者,因为user1533116声明:“一些日期值为空。对不起,@Steve,我无意中编辑了你的帖子。已回滚到原始版本。我删除了System.Data.OleDb.OleDbCommand部分,因此没有更改它的性质。我一定是瞎了。@dash,好吧,不过你的编辑是对的。让我还原您的更改:-)我唯一的另一个评论是,您不能以这种方式设置值,因为DBNull.value和DateTime之间没有转换-不幸的是,您不能以这种方式使用三元[conditional]运算符。但是,它仍然是+1,因为您是唯一在上下文中提到DateTime.MinValue的人。@dash,对,我没有注意到这一点。但是,将强制转换添加到对象是可行的。确切地说,你的答案更好。DateTime
确实不能为null,DateTime?
但是,can:-)我假设后者,因为user1533116声明:“一些日期值为null”。对不起,@Steve,我无意中编辑了你的帖子。已回滚到原始版本。我删除了System.Data.OleDb.OleDbCommand部分,因此没有更改它的性质。我一定是瞎了。@dash,好吧,不过你的编辑是对的。让我还原您的更改:-)我唯一的另一个评论是,您不能以这种方式设置值,因为DBNull.value和DateTime之间没有转换-您不能使用ternar