Casting Result from SQL Query - System.InvalidCastException - c#

I am trying to store the result of a select query. The value being returned is stored as an integer in Sqlite.
I decided to try what was presented in this answer: https://stackoverflow.com/a/870771
My code is currently:
cmd.CommandText = "SELECT id FROM TVShows WHERE id = #id";
cmd.Parameters.Add(new SQLiteParameter("#id", id));
conn.Open();
object result = ConvertFromDBVal<int>(cmd.ExecuteScalar());
private T ConvertFromDBVal<T>(object obj)
{
if (obj == null || obj == DBNull.Value)
{
return default(T); // returns the default value for the type
}
else
{
return (T)obj;
}
}
However, I am receiving the error:
System.InvalidCastException at this line:
return (T)obj;
If I simply try and store the result of cmd.ExecuteScalar()) as an int, I get the same error.
I must admit I don't completely understand this function and so if someone could shed some light on that as well, I'd greatly appreciate it!

Per the comments, you cannot cast a long to an int. By passing in long, you will not have a cast exception.
long result = ConvertFromDBVal<long>(cmd.ExecuteScalar());

Related

How to handle if ExecuteScalar is null

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

Cast to int on SqlCommand-ExecuteScalar error handling

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...
}

How to convert a value to a type that is passed as a parameter

I have a function that will execute aggregated function (ie. COUNT(),MIN(), MAX())
sometimes I want to return int, double, date, datetime....
I'm having an issue trying to convert the return value
the following line is giving me an error value = Convert.ChangeType(vv, typeof(T) );
Here is the error
Cannot implicitly convert type 'object' to 'T'. An explicit conversion exists (are you missing a cast?)
Here is my method
public T getValue<T>(string query, List<MySqlParameter> pars)
{
T value;
using (var conn = new MySqlConnection(conn_string))
using (var cmd = new MySqlCommand(query, conn))
{
if (pars != null)
{
foreach (MySqlParameter p in pars)
{
cmd.Parameters.Add(p);
}
}
conn.Open();
try
{
object vv = (T)cmd.ExecuteScalar();
if (vv != null)
{
value = Convert.ChangeType(vv, typeof(T) );
}
} catch(Exception ex){
Common.Alert(ex.ToString(), "SQL Error");
value = default(T);
} finally {
conn.Close();
}
}
return value;
}
And when I use this method I use this
int cnt = db.getValue<int>(query, params);
Your code doesn't make a lot of sense. First you cast to T, then if it's not null, you convert it to T? The conversion is useless. I think it's worth pointing out that the particular error you're getting ("Cannot implicitly convert type 'object' to 'T'.") is because Convert.ChangeType returns an object, so it's often casted immediately after calling:
value = (T)Convert.ChangeType(v, typeof(T));
In your case, you might want to do this:
object rawValue = cmd.ExecuteScalar();
value = (T)Convert.ChangeType(rawValue, typeof(T));
Note that if rawValue is null and T is a value type (struct, e.g. int), this (portion of) code will throw an exception. This is probably better than silently letting the value be default(T).

Returning int from object x = ExecuteScalar() with nulls

might not be the best approach to the problem, but I'm trying to query my user database in order to find out if a new user can register himself; there are 3 possible replies from the stored procedure:
1 - User is registered (Can't register, message A)
0 - User is not registered (Can register, success)
null - User is not loaded on database (Can't register, message B)
My class is as follows:
public int ValidateUser(string bi)
{
SqlConnection cnConnect = new SqlConnection();
cnConnect.ConnectionString = strConnect;
cnConnect.Open();
SqlCommand checkUser = new SqlCommand("sp_RegistaConnect", cnConnect);
checkUser.CommandType = CommandType.StoredProcedure;
checkUser.Parameters.Add(new SqlParameter("#opt", 5));
checkUser.Parameters.Add(new SqlParameter("#bi", bi));
object userResult = checkUser.ExecuteScalar();
cnConnect.Close();
if (userResult is DBNull)
{
return 2;
}
else
{
int intReturn = (int)userResult;
return intReturn;
}
}
My problem is, it always says the specified cast is not valid when converting to int. But one I ruled out the DBNull results, shouldn't it always be possible to cast to int? Maybe my brain is dying.
EDITED: My brain *was* dying - the database was returning a bool (bit)
Problem is, when a null value returns from the database I always get an error - Object reference not set to an instance of an object.
I also tryed a simpler version, with the same error result:
object userResult = checkUser.ExecuteScalar();
int intReturn = (int)(!Convert.IsDBNull(userResult) ? userResult : 2);
return intReturn;
How can I cast my sql return into an int, while dealing with null results?

Int32.TryParse() or (int?)command.ExecuteScalar()

I have a SQL query which returns only one field - an ID of type INT.
And I have to use it as integer in C# code.
Which way is faster and uses less memory?
int id;
if(Int32.TryParse(command.ExecuteScalar().ToString(), out id))
{
// use id
}
or
int? id = (int?)command.ExecuteScalar();
if(id.HasValue)
{
// use id.Value
}
or
int? id = command.ExecuteScalar() as int?;
if(id.HasValue)
{
// use id.Value
}
The difference between the three performance wise is negligible. The bottleneck is moving the data from the DB to your app, not a trivial cast or method call.
I would go with:
int? id = (int?)command.ExecuteScalar();
if(id.HasValue)
{
// use id.Value
}
It fails earlier, if one day people change the command to return a string or a date, at least it will crash and you will have a chance to fix it.
I would also just go with a simple int cast IF I always expected the command to return a single result.
Note, I usually prefer returning an out param than doing the execute scalar, execute scalar feels fragile (the convention that the first column in the first row is a return value does not sit right for me).
If you expect the command to return null, you should keep in mind that database null (DBNull) is not the same as .NET null. So, conversion of DBNull to int? would fail.
I'd suggest the following:
object result = command.ExecuteScalar();
int? id = (int?)(!Convert.IsDBNull(result) ? result : null);
If none of the above works (especially for users who are battling with MySQL)
why don't you try the following?
int id = Convert.ToInt32(cmd.ExecuteScalar().ToString());
int Result = int.Parse(Command.ExecuteScalar().ToString());
will work in C#.
The latter. Convert.ToInt32() is also an option.
Use id.HasValue for maximum Nullable Type cool-factor!
if ((Int32)cmd.ExecuteScalar () ** 1) //en esta parece qu esta el error pero no lo veo
{
Response.Redirect("Default.aspx");
}
else
{
Response.Redirect("error.htm") ;
}

Categories

Resources