I have the following code that inserts some data into an Access table. It starts with a comma delimited line that I split into a string array, then add the array elements as parameters:
string line = "one\ttwo\t\tfour";
string[] values = line.Split('\t');
using (OleDbCommand com = new OleDbCommand("INSERT INTO [MyTable] (" +
"[Field1], [Field2], [Field3], [Field4] "
") VALUES (" +
"?, ?, ?, ?" +
")", con))
{
com.Parameters.Add("#p0", OleDbType.Char, 255).Value = (object)values[0] ?? DBNull.Value;
com.Parameters.Add("#p1", OleDbType.Char, 255).Value = (object)values[1] ?? DBNull.Value;
com.Parameters.Add("#p2", OleDbType.Char, 255).Value = (object)values[2] ?? DBNull.Value;
com.Parameters.Add("#p3", OleDbType.Char, 255).Value = (object)values[3] ?? DBNull.Value;
com.ExecuteNonQuery();
}
In the above example, #p2 will not have a value. It gets inserted into the Access table as a blank value, instead of a null value. At least I think I'm explaining that correctly. If I query for Field3 is Null I get no results. If I query for Field3 = "" I do get results. Does it matter if it's blank or null? Is there a 'preferred' option?
Thanks!
Well, null is definitely not the same as an empty string. So, yes, it matters. But only in your domain. So in other words, if the field isn't really nullable and Access is interpreting DBNull.Value as an empty string, then you just have to keep that in mind when looking for rows with no value. If the column were nullable in Access you wouldn't be seeing this behavior.
However, if the field in nullable, then I would recommend you actually just send in null instead of DBNull.Value. So, in other words:
values[0];
instead of:
(object)values[0] ?? DBNull.Value;
Original statement:
com.Parameters.Add("#p2", OleDbType.Char, 255).Value = (object)values[2] ?? DBNull.Value;
From the description it is sending the empty string '' from values[2], not the DBNull.Value. I would explicitly convert the empty string (or null) rather than using the null-coalescing operator (??):
com.Parameters.Add("#p2", OleDbType.Char, 255).Value = String.IsNullOrEmpty(values[2]) ? DBNull.Value : values[2];
Added: As the type-specification (OleDbType.Char) is preventing this from sending DBNull to the database, I would revert to AddWithValue:
com.Parameters.AddWithValue("#p2", String.IsNullOrEmpty(values[2]) ? DBNull.Value : values[2]);
This doesn't specify the type so should accept DBNull or the string. I prefer this approach anyway: if we specify the type we need to ensure that it is entirely consistent with the field data-type -> let C# work this out.
Related
Next code is giving me an exception:
cmd.CommandText = #"insert Table ";
cmd.CommandText += #"(StartTime,
EndTime)
values(#StartTime,
#EndTime)
SELECT CAST(scope_identity() AS int)";
cmd.Parameters.AddWithValue ( "#StartTime", DBNull.Value );
cmd.Parameters.AddWithValue ( "#EndTime", DBNull.Value );
cmd.ExecuteScalar();
The exception I am getting is Must declare '#StartTime' variable and same thing for #EndTime. Isn't the DBNull.Value used for things like this, what am I doing wrong?
I think the reason is the fact you are using AddWithValue.
You see, AddWithValue have to infer the data type of the parameter from the value (and meta data, if exists). When you use DBNull.Value and an inline SQL (as apposed to a stored procedure), there is simply no way to infer the data type.
Change the AddWithValue to Add:
cmd.Parameters.Add("#StartTime", SqlDbType.DateTime).Value = DBNull.Value;
cmd.Parameters.Add("#EndTime", SqlDbType.DateTime).Value = DBNull.Value
For more information, read Can we stop using AddWithValue() already?
I have a SQL table where column is set to null. Now I am passing the null value from code via stored procedure and it throws an error which is, Procedure or function 'MyStoredProcedure' expects parameter '#Parameter', which was not supplied.
Now Confusing part for me is, if I add null condition and than pass DBNull.Value, it works fine but if I pass direct parameter which could be null than it throws error. I am trying to understand why? Am I missing something here?
Note: Just for information, passing parameter could be null based on the requirement.
Code:
string connString = _dbContext.Database.Connection.ConnectionString;
using (SqlConnection connection = new SqlConnection(connString))
{
connection.Open();
SqlCommand cmd = new SqlCommand("MyStoredProcedure", connection);
cmd.CommandType = CommandType.StoredProcedure;
scheduledEndDateTime = !string.IsNullOrEmpty(bulkUpdateSchedule.EndDate) && !string.IsNullOrEmpty(bulkUpdateSchedule.EndTime)
? (DateTime?)
Convert.ToDateTime(bulkUpdateSchedule.EndDate + " " + bulkUpdateSchedule.EndTime)
: null;
//This Fails
cmd.Parameters.AddWithValue("#scheduledEndDateTime", scheduledEndDateTime);
//This Works
if (scheduledEndDateTime != null)
{
cmd.Parameters.AddWithValue("#scheduledEndDateTime", scheduledEndDateTime);
}
else
{
cmd.Parameters.AddWithValue("#scheduledEndDateTime", DBNull.Value);
}
cmd.ExecuteReader();
connection.Close();
}
Stored Procedure:
ALTER PROCEDURE [dbo].[InsertScheduledBulkUpdateRecords]
#scheduledEndDateTime DATETIME,
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO ScheduledBulkUpdate (ScheduledEndDateTime)
VALUES (#scheduledEndDateTime)
END
Table Structure screen shot:
You've pretty much answered your own question null and DBNull.Value are different things. Where DBNull.Value means something to the database provider than null doesn't.
From MSDN on DBNull:
Do not confuse the notion of null in an object-oriented programming
language with a DBNull object. In an object-oriented programming
language, null means the absence of a reference to an object. DBNull
represents an uninitialized variant or nonexistent database column.
Code:
private void DoSomethingWithDatabase(string f1, int f2)
{
SqlCommand myCommand = new SqlCommand("SELECT Field1,Field2,Field3 FROM MyTable WHERE Field1 = #F1 AND Field2 = #F2", this.myConn);
myCommand.Parameters.Add("#F1", System.Data.SqlDbType.VarChar);
myCommand.Parameters.Add("#F2", System.Data.SqlDbType.Int);
if (f1 == "")
myCommand.Parameters["#F1"].Value = DBNull.Value;
else
myCommand.Parameters["#F1"].Value = f1;
if (f2 < 0)
myCommand.Parameters["#F2"].Value = DBNull.Value;
else
myCommand.Parameters["#F2"].Value = f2;
// code to do stuff with the results here
}
The server is a Microsoft SQL Server instance.
The database table MyTable contains fields which are nullable. Therefore null is a valid value to search on when performing the query.
From my reading, and also from testing code like this, doing something like what I did here doesn't work properly because apparently you can't do an "equals null" comparison this way - you're supposed to do "IS NULL".
It looks like you can correct this and make it work by setting ANSI_NULL to OFF (as per https://msdn.microsoft.com/en-us/library/ms188048.aspx) but it also indicates this method is deprecated and should not be used.
That article suggests you can use an OR operator to do something like WHERE Field1 = 25 OR Field1 IS NULL. The problem is, with a single call to this function, I want to check for either null and only null, or for the given constant value and nothing else.
So far, it seems like I need to basically build the query piece by piece, string by string, to account for the possibility of NULL values. So I'd need to do something like:
string theQuery = "SELECT Field1,Field2,Field3 FROM MyTable WHERE ";
if (f1 == "")
theQuery += "Field1 IS NULL ";
else
theQuery += "Field1 = #F1 ";
// ...
SqlCommand myCommand = new SqlCommand(theQuery, this.myConn);
if (f1 == "")
{
myCommand.Parameters.Add("#F1", System.Data.SqlDbType.VarChar);
myCommand.Parameters["#F1"].Value = f1;
}
// ...
Is this really how it needs to be done? Is there a more efficient way to do this without repeating that if block and by using parameters rather than concatenating a query string together?
(Notes: An empty string is converted to a NULL here for the example. In the scenario I'm actually working with, empty strings are never used, but instead NULL is stored. The database is out of my control, so I can't just say "change all your NULLs to empty strings". Same goes for the ints - if we pass, say, -1 into the function it should be testing for a null value. Bad practice? Maybe, but the database itself is not in my control, only the code to access it is.)
Why not using:
string theQuery = "SELECT Field1, Field2, Field3 FROM MyTable WHERE ISNULL(Field1,'') = #F1";
?
That way you get rid of your if block and your null values are interpreted as an empty string, like your f1 variable.
SQL Server has a function called ISNULL(Column,Value) where you can specify one column to check and set a Default Value in case this Column is NULL.
You can check here
You could do something like
WHERE ISNULL(Field, '') = #F1
In that case, NULL fields are treated like empty strings. Another way would be:
WHERE Field IS NULL OR Field = #1
The way you are dealing with NULLs is the right way. Maybe you could use a helper method like this one:
private string AppendParameter(string query, string parameterName, string parameterValue, SqlParameterCollection parameters)
{
if (string.IsNullOrEmpty(parameterValue))
query += "Field1 IS NULL ";
else
{
query += "Field1 = " + parameterName + " ";
parameters.AddWithValue(parameterName, parameterValue);
}
return query;
}
SqlCommand myCommand = new SqlCommand(#"SELECT Field1,Field2,Field3
FROM MyTable
WHERE
( (#F1 IS NULL AND [field1] IS NULL) OR [field1] = #F1 ) AND
( (#F2 IS NULL AND [field2] IS NULL) OR [field2] = #F2 );", this.myconn);
myCommand.Parameters.Add("#F1", System.Data.SqlDbType.VarChar).Value = DBNull.Value;
myCommand.Parameters.Add("#F2", System.Data.SqlDbType.Int).Value = DBNull.Value;
if (!string.IsNullOrEmpty(f1))
myCommand.Parameters["#F1"].Value = f1;
if (f2 != -1)
myCommand.Parameters["#F2"].Value = f2;
This would utilize indexes on fields.
If you want to avoid if blocks, you can probably change the query into something like this:
SELECT Field1,Field2,Field3 FROM MyTable
WHERE COALESCE(Field1,'') = #F1 AND COALESCE(Field2,-1) = #F2
I tried to pass some variables into a parameterized query but when the value is NULL it throws an exception that says the value is not provided.
How can I fix that without an if or something like that?
My code is this
var cmdPersona_Log = new SqlCommand();
cmdPersona_Log.Parameters.Clear();
cmdPersona_Log.Connection = mySqlConnection;
cmdPersona_Log.CommandType = CommandType.Text;
cmdPersona_Log.CommandText = #"INSERT INTO [Tomin].[TominRH].[Persona_Log] "
+ "([Id_Action],[Id_User],[Id_Date],[Id_Entidad],[Nombre],[Paterno],[Materno],[Sexo],[Id_Nacionalidad])"
+ " Values (1, 'Admin', #fecha, #id_entidad, #nombre, #paterno, #materno, 1, 52)";
cmdPersona_Log.Parameters.Add("#fecha", DateTime.Now);
cmdPersona_Log.Parameters.Add("#id_entidad", dbRow["CUENTA"]);
cmdPersona_Log.Parameters.Add("#nombre", nombre);
cmdPersona_Log.Parameters.Add("#paterno", paterno);
cmdPersona_Log.Parameters.Add("#materno", materno);
cmdPersona_Log.ExecuteNonQuery();
I will assume that your problem is that the underlying field doesn't support nulls. If this is the case, you could do something like this
cmdPersona_Log.Parameters.Add("#nombre", nombre ?? string.Empty);
cmdPersona_Log.Parameters.Add("#paterno", paterno ?? string.Empty);
cmdPersona_Log.Parameters.Add("#materno", materno ?? string.Empty);
You'll be inserting an empty string in case you have a null using the null-coalescing operator.
In my ASP.net C# web project I have a query command object that has parameters. I use the following code to fill the parameters:
DbCommand command = conn.CreateCommand();
command.CommandText = query;
DbParameter param = command.CreateParameter();
param.ParameterName = parameter;
param.DbType = DbType.String;
param.Value = value;
This code works for all strings except for empty ones. If I would leave an input field blank, it would pass the value as "". If this happens I receive the following exception:
ORA-01400: cannot insert NULL into (string)
Is there a way that would allow me to insert blank strings into the database?
I use an Oracle database and I'm using System.Data.OracleClient as provider.
If you want to insert an empty string, you have to allow NULL values. Otherwise Oracle silently converts the empty string into NULL and you'll get the exception.
Another option would be to insert an empty string with a space ' ' but i think that would be a pain.
Here are further informations on why Oracle does it this (non standard) way:
Why does Oracle 9i treat an empty string as NULL?
If the value is null, set param.Value = DBNull.Value, rather than setting it to null:
if (value == null)
{
param.Value = DBNull.Value;
}
else
{
param.Value = value;
}
try
param.Value = string.IsNullOrEmpty(value) ? DBNull.Value : value;