I have code that is possibly fragile. This statement here
int countDis = (int)cmd.ExecuteScalar();
If I change the stored procedure to not return ANYTHING, then that casting to (int) is going to blow up. If I simply remove it, then I cannot compile.
What is the best code practice for defensive coding in this situation?
Just change the code as:
int countDis = Convert.ToInt32(cmd.ExecuteScalar());
This will ensure that even if ExecuteScalar returns null, as result of not selecting anything in stored procedure, countDis will have a value of 0. Because Convert.ToInt32(null) = 0.
Update (10/12/2018)
Safer version. Thanks #Moe for highlighting DBNull case.
object result = cmd.ExecuteScalar();
result = (result == DBNull.Value) ? null : result;
int countDis = Convert.ToInt32(result);
I usually use nullable types. e.g. :
string str;
int? countDis = cmd.ExecuteScalar() as int?;
if (countDis == null)
str = "count is null";
else
str = "Count is : " + countDis.Value;
This will work for whether ExecuteScalar returns null or DBNull.Value.
You can check the scalar value before cast.
var result = cmd.ExecuteScalar();
int countDis =result != null ? int.Parse(result) : 0;
Because ExecuteScalar can return DBNull, the best way there I found is:
var result = cmd.ExecuteScalar();
int countDis = result != null ? Convert.ToInt32(result) : 0;
if you treat a result of DBNull.Value as the same as null in that they should both be 0, you can use a single line, though you're still using a temporary variable. I won't speak of execution speed:
int countDis = int.TryParse(cmd.ExecuteScalar()?.ToString(), out int temp) ? temp : 0
You can use to get as Object, and check its type then take your decision:
object obj = cmd.ExecuteScalar();
if (obj.GetType() == typeof(string))
{
//you can do your stuff with STRING
}
else if (obj.GetType() == typeof(int))
{
//you can do your stuff with INT
}
else
{
//add here ANYOTHER type you many want in future...
}
Related
I would like your help on how to handle and exception in C# if ExecuteScalar is null. Am trying it but am getting a null reference exceprion. This is my code
public async Task<int> SumItemAsync()
{
Object data = await db.ExecuteScalarAsync<int>("SELECT
SUM(Amount) FROM Spent");
if (data != null)
{
return Convert.ToInt32(data);
}
else
{
return 0;
}
}
I believe that the problem is that your query returns null but you tell ExecuteScalarAsync that is should be an int. Change it to a nullable int.
var data = db.ExecuteScalarAsync<int?>("SELECT SUM(Amount) FROM Spent")
return data ?? 0;
You can then simplify the return expression a little bit.
I actually didn't solve it by using your code but you mentioned that my query returns null but I tell ExecuteScalarAsync that is should be an int. So from your statement I did it like this and it worked. Thanks anyway
public async Task SumItemAsync()
{
var data = await db.ExecuteScalarAsync<String>("SELECT SUM(TotalAmount) FROM Spent");
if (data != null)
{
return data;
}
else
{
return "0.00";
}
I am trying to populate a combobox with a list my query returns. When I execute my program it gives me a specified cast is not valid error ( I have it execute on page load event). Every field in the database I have to work with can be null except the primary key. So I tried using DBNull.Value but it can't get my (int)reader fields to work. I have supplied my code below for a better understanding. How can I get my (int)reader's to work with my statements, so they can read when there is a null value?
CustData cd = new CustData();
cd.CustomerID = (int)reader["CustomerID"];
cd.Name = reader["Name"] != DBNull.Value ? reader["Name"].ToString() : string.Empty;
cd.ShippingAddress = reader["ShippingAddress"] != DBNull.Value ? reader["ShippingAddress"].ToString() : string.Empty;
cd.ShippingCity = reader["ShippingCity"] != DBNull.Value ? reader["ShippingCity"].ToString() : string.Empty;
cd.ShippingState = reader["ShippingState"] != DBNull.Value ? reader["ShippingState"].ToString() : string.Empty;
cd.ShippingZip = (int)reader["ShippingZip"];
cd.BillingAddress = reader["BillingAddress"] != DBNull.Value ? reader["BillingAddress"].ToString() : string.Empty;
cd.BillingCity = reader["BillingCity"] != DBNull.Value ? reader["BillingCity"].ToString() : string.Empty;
cd.BillingState = reader["BillingState"] != DBNull.Value ? reader["BillingState"].ToString() : string.Empty;
cd.BillingZip = (int)reader["BillingZip"];
cd.Territory = reader["Territory"] != DBNull.Value ? reader["Territory"].ToString() : string.Empty;
cd.Category = reader["Category"] != DBNull.Value ? reader["Category"].ToString() : string.Emptyy
That is because int is not nullable. You need to use int? or nullable<int> (long hand) to allow it to be an int OR a null value.
You can then use the usual .HasValue and .Value etc to get the value from the item.
EDIT: To enhance the visibility of my comment to this answer. I would advise against checking for NULL and storing Zero into your property because then when you save back you are changing a Null to a Zero even though nothing has been changed by the system. Now, reports etc may distinguish between NULL and Zero (very often) and could start doing strange things!
Null does NOT equal zero!! If you assume it does as a work around... What happens if I truly do want to record zero? How do you differentiate between a real zero and a "was null now zero" trick? Do it right, save yourself the pain!
Use nullable int, or just make your control for your int's too
reader["ShippingZip"] != DBNull.Value ? (int)reader["ShippingZip"] : default(int);
You should use a nullable int for your variable and cast it, like (int?). Int can only have a value; nullable types can also be null. When you use a nullable type, you can look at the property .HasValue. Here is the MSDN page: http://msdn.microsoft.com/en-us/library/2cf62fcy.aspx
I have a table which contains null values and I need to get data from the table using SqlDataReader. I can't figure out how I can safely cast DBNull to int.
I'm doing it in this way at the moment:
...
reader = command.ExecuteReader();
while (reader.Read()) {
int y = (reader["PublicationYear"] != null) ? Convert.ToInt32(reader["PublicationYear"]) : 0;
...
}
...
but getting a Object cannot be cast from DBNull to other types. when PublicationYear is null.
How can I get the value safely?
Thanks.
You should compare reader["PublicationYear"] to DBNull.Value, not null.
DBNull is not the same as null. You should try something like this instead:
int y = (reader["PublicationYear"] != DBNull.Value) ? ...
int ord = reader.GetOrdinal("PublicationYear");
int y = reader.IsDBNull(ord) ? 0 : reader.GetInt32(ord);
Or, alternatively:
object obj = reader["PublicationYear"];
int y = Convert.IsDBNull(obj) ? 0 : (int)obj;
You should explicitly check if the value returned is of type DBNull
while (reader.Read()) {
int y = (!reader["PublicationYear"] is DBNull) ? Convert.ToInt32(reader["PublicationYear"]) : 0;
...
}
In fact, you can do this comparison by value as well as type:
reader["PublicationYear"] != DBNull.Value
In short - you can expect DBNull to be returned for nulls from the database, rather than null itself.
as an alternative you can do the following.
as you are converting DBNull to 0, alter the procedure that does the select. so that the select itself returns zero for a null value.
snippet to demonstrate the idea
SELECT ...
,ISNULL (PublicationYear, 0) as PublicationYear
...
FROM sometable
advantage of this is that, no additional checking is needed in your code.
Change
reader["PublicationYear"] != null
to
reader["PublicationYear"] != DBNull.Value
That's the error: (reader["PublicationYear"] != null)
You should test for DBNull.Value....
Change your test from (reader["PublicationYear"] != null) to (reader["PublicationYear"] != DBNull.Value).
Database null values should be compared with DBNull.Value:
reader = command.ExecuteReader();
while (reader.Read())
{
int y = (reader["PublicationYear"] != DBNull.Value) ? Convert.ToInt32(reader["PublicationYear"]) : 0;
...
}
I have Views field from one of my tables in the database. At first i allowed it to take nulls, and now it disallowed it to take null. The problem is that that exception is being thrown when i convert the SqlReader instance to an int..here is the code:
try
{
conn.Open();
SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
if (dr != null && dr.Read() && dr["Views"] != null && dr["PageNumber"] != null && dr["Replies"]!=null)
{
Name = dr["Name"].ToString();
ThreadName = dr["ThreadTitle"].ToString();
Views = int.Parse(dr["Views"].ToString());//it is being thrown here when i try to convert it to an int..How can i prevent that mistake from being thrown?
Replies = int.Parse(dr["Replies"].ToString());
Topic = dr["Theme"].ToString();
Subtopic = dr["Topics"].ToString();
PageNumber = int.Parse(dr["PageNumber"].ToString());
Time = (DateTime)dr["Time"];
}
dr.Close();
}
Try
View = dr["Views"] as int? ?? 0;
If the value in the db is null then above it's being cast into a nullable int which can accept nulls.
Use the coalesce operator ?? to set the value of View to some other value (in this case 0) if the value in the database IS null.
You can use int.TryParse() to avoid the error. If the probem is just the null, I would recommend to use System.Convert to handle these situations, because it's safer and clear:
View = System.Convert.ToInt32(dr["Views"]);
To avoid exception while convertion, use Int32.TryParse always.
How about
if(dr["Views"] != DBNull)
{
// do your parse here
}
I have a dataset of values, which I need to put into a textbox. However, there are some decimal and double type values in my dataset, so I need to cast them toString(). Furthermore, sometimes the dataset values are empty, so before casting toString() I need to check whether there is actually a value there or not.
This is sample line:
I need code that does something like this...
if(ds.Tables[0].Rows[0].Field<decimal>("IndexPrethodni") !=null or something){
Convert.ToString(ds.Tables[0].Rows[0].Field<decimal>("IndexPrethodni"));
}
I known decimal is not a nullable type. Is there any easy solution to achieve my desired result?
Personally, I'd wrap it like so:
var col = ds.Tables[0].Columns["IndexPrethodni"];
var row = ds.Tables[0].Rows[0];
if (!row.IsNull(col))
{
string s = row[col].ToString();
...
}
(the "via a column object" is the most direct (= fastest) indexer)
Try
if(ds.Tables[0].Rows[0]["IndexPrethodni"] != DBNull.Value)
You can also check the value using Convert.IsDBNull().
I normally use a method such like:
public T GetValue<T>(object source)
{
if (Convert.IsDBNull(source))
return default(T);
return (T)source;
}
E.g.
using (var reader = command.ExecuteReader())
{
if (reader.Read())
{
return GetValue<string>(reader["SomeColumn"]);
}
}
check for DBNull
if(ds.Tables[0].Rows[0].Field("IndexPrethodni") != DBNull.Value) {
//convert to string
}
TO use Convert.ToString you need not to check for null value, because if there will null then also it will not give any error and return blank..
You need to check the value isnt DBNull, so something like this would work
object columnValue = ds.Tables[0].Rows[0].Field<decimal>("IndexPrethodni");
if (object != System.DBNull.Value) Convert.ToString(columnValue);
Why don't you use the nullable type to check for a value?
if( ds.Tables[ 0 ].Rows[ 0 ].Field<decimal?>( "IndexPrethodni" ).HasValue )
{
Convert.ToString( ds.Tables[ 0 ].Rows[ 0 ].Field<decimal>( "IndexPrethodni" ) );
}
If we are checking for decimal value is null or not before converting to other type
decimal? d;
if (!d.HasValue)
{
//d is null
}