简体   繁体   中英

Parameterized query and NULL DateTime value

I'm working a program that is pulling a string field from an access database, separating out a name (first and last) from a date then save the name separately from the date in a different access database.

I've got everything done except some of the date values are null so I need to parametrize the SQL but I haven't been able to figure out how to do make the parametrization work.

I've put in dummy values for the variable and it adds them to the table just fine. I've cut out the other variables in the code snippet below since they're all repeats of what's there. os is a list holding data from a structure.

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();
}

You need to "convert" null to DBNull.Value . One way to achieve that, assuming QADate is a nullable DateTime (so DateTime?) might be:

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

?? being the null-coalescing operator .

Edit: You might actually need to cast to make sure both operands are of the same type:

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

Also, why don't you use a parameter for QASignature?? Why are you "inlining" that value? I don't know what QASignature would contain, but this leaves you vulnerable to SQL Injection .

And finally, why are you using ExecuteReader() for an insert? Why not use ExecuteNonQuery() ?

Something like the following should be what you want:

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
} 

If os.QADate is nullable ( DateTime? or System.Nullable<DateTime> ), then you would do the following:

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});
}

Note that you shouldn't mix string concatenation and parameters like in your original example - it's one or the other! And really, it should be just parameterization to guard against SQL Injection, and to gain other benefits (like easier typing and, in some RDBMS, parameterized queries perform better).

Also note that OleDBCommand does not benefit from named parameters - parameters must be added to the query in the order they appear in the SQL. This is why the SQL Query contains two question marks - they are simply placeholders.

DateTime cannot be null, if the value is not initialized it is DateTime.MinValue. You need to test for this case and use the parameters also for the string values.

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(); 
} 

By the way, an insert statement usually is executed by ExecuteNonQuery

Use DBNull.Value :

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

As a side note, using OleDbParameterCollection.AddWithValue automatically infers the data type and allows you to shorten your code:

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

Consider using the Nullable(of T) structure. Then you can set it only if there is actually a variable in your source object. Otherwise the value is set to Null and passes itself nicely into SQL Parameters. A lot of the old TableAdapter classes and newer EntityFramework objects work with the Nullable (of T) structure as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM