Invalid cast exception when reading result from SQLDataReader - c#

My stored procedure:
#UserName nvarchar(64),
AS
BEGIN
SELECT MPU.UserName, SUM(TS.Monday)as Monday //TS.Monday contains float value
FROM dbo.MapTask MT JOIN dbo.MapPU MPU
ON MPU.ID = MT.MPUID
JOIN dbo.TimeSheet TS
ON MT.TMSID = TS.ID
WHERE MT.StartDate = #StartDate_int and MPU.UserName = #UserName
GROUP BY MPU.UserName
END
In my C# code
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
float monday = (float)reader["Monday"]; // Invalid cast exception
}
Can somebody tell me what I did wrong ? Thank you.

My guess is that the value is being returned as a boxed double instead of float. When you unbox the type has to be exactly right. So assuming I'm right and it's not decimal or something like that, you could use:
float monday = (float) (double) reader["Monday"];
and it would work. That's pretty ugly though. If you use SqlDataReader.GetFloat it should get it right if it's genuinely a single-precision value, and it's clearer (IMO) what's going on.
On the other hand, your data could actually be coming back from the database as a double, in which case you should (IMO) use:
float monday = (float) reader.GetDouble(column);
As an aside, are you sure that float is actually the most appropriate type here in the first place? Often decimal is more appropriate...

A sql float is a .NET Double, see on the msdn.
Try casting to a double.

I also had a similar issue and ended up doing this:
if (!oDR.IsDBNull(0))
Rating = (float)oDR.GetSqlDecimal(0).Value;
oDR.GetFloat(0) was returning and invalid cast exception when accessing the result of a SELECT AVG(...).
HTH

float monday = Convert.ToDouble(reader["Monday"]);
would be a nice approach. I am trying to find a solution for over an hour and it fails here. now it works fine.

Related

Unboxing a boxed float to an int

I'm preparing for an exam and stumbled over a question regarding boxing/unboxing.
I always thought if i box let's say a float like this:
float x = 4.5f;
object o = x;
If a want a value type variable back from o, I will have to unbox it to a float.
float y = (float)o;
This should throw an exception:
int z = int(o);
If I want to cast the value stored in o to an int I will have to unbox it first and cast afterwards like this:
int z = (int)(float)o;
Now the question i stumbled upon:
Suppose you have a method like this:
public static void FloorTemperature(float degrees) {
object degreesRef = degrees;
`xxx`
Console.WriteLine(result);
}
You need to ensure the application does not throw exceptions on invalid conversions. Which code segment should you insert for xxx (I think invalid conversion are invalid cast exceptions):
(a) int result = (int)degreesRef;
(b) int result = (int)(float)degreesRef;
The correct solution is (a), but to me (b) looks correct. So can you please enlighten me? What am I missing?
Kind regards
You aren't missing anything
The answer should be (b) because:
(a) throws an exception since you are trying to cast object to int.
(b) is correct since you first cast it to float then you cast it to int which rounds it but doesn't throw an exception.

why is this specified cast not valid??

i use the following code to map data from sql reader to C# Objects. the Power is of data type float in both code and sql database .. y is the cast error message occuring?
private Entity.PanelDetail MapDataReader(SqlDataReader dataReader)
{
Entity.PanelDetail panelDetail = new Entity.PanelDetail();
panelDetail.IdPanelDetail = DataReaderExtensions.GetStringOrNull(dataReader, "idPanelDetail");
panelDetail.IdDeviceDetail = DataReaderExtensions.GetStringOrNull(dataReader, "idDeviceDetail");
panelDetail.Power = DataReaderExtensions.GetFloatOrNull(dataReader, "Power");
panelDetail.Current = DataReaderExtensions.GetFloatOrNull(dataReader, "Current");
panelDetail.Length = DataReaderExtensions.GetFloatOrNull(dataReader, "Length");
panelDetail.Width = DataReaderExtensions.GetFloatOrNull(dataReader, "Width");
panelDetail.CreatedBy = DataReaderExtensions.GetStringOrNull(dataReader, "CreatedBy");
panelDetail.CreationDate = DataReaderExtensions.GetDateTimeOrNull(dataReader, "CreationDate");
panelDetail.ModifiedBy = DataReaderExtensions.GetStringOrNull(dataReader, "ModifiedBy");
panelDetail.ModifiedDate = DataReaderExtensions.GetDateTimeOrNull(dataReader, "ModifiedDate");
panelDetail.IsActive = DataReaderExtensions.GetBoolOrNull(dataReader, "IsActive");
panelDetail.IsDeleted = DataReaderExtensions.GetBoolOrNull(dataReader, "IsDeleted");
return panelDetail;
}
My guess that the value is being returned as a boxed double instead of float. Try to use
(float) dataReader.GetDouble(fieldOrdinal);
See Mapping CLR Parameter Data
I would make a good bet that the data type being return is actually a (boxed) double.
Update: Actually I just found that an SQL float maps to a .NET double on MSDN (so yes this is your problem): http://msdn.microsoft.com/en-us/library/ms131092.aspx
Try this as a test:
(float)dataReader.GetDouble(fieldOrdinal);
The reason is that SQL Float is double in .net. You can see the complete mapping here. Therefore, as others have suggested you need to read double and then try to cast it to float.
(float)dataReader.GetDouble("Power");

Function Int32.TryParse("23.0") returning false - C# MVC4

In my code i try to get browser version for charging the good css file, but this code doesn't work, and i don't see my error...
I've simply try first with a Convert.ToInt32 but don't works too...
public ActionResult Index()
{
ViewBag.logged = false;
ViewBag.BrowserName = Request.Browser.Browser.ToString();
Int32 v = 0;
string version = Request.Browser.Version;
if (version != null)
{
bool result = Int32.TryParse(version, out v);
}
ViewBag.BrowserVersion = v;
return View();
}
In my debugger :
version => string : "23.0"
v => int 0
result => false
Request.Browser.Version => string "23.0"
This is by design.
Parsing a version string would work better with System.Version.
You can, alternatively, parse it to a float and then see if a lossless conversion to Int32 can be made.
I fully agree with Andrei's answer; that's the approach you should take.
However, I think it's important to note that there is a way to parse int values from strings such as "23.0": it can be done using this overload of int.TryParse() which allows you to pass NumberStyles flags as parameters.
Concretely, after executing this code:
int v;
var wasParsedOK = Int32.TryParse(
"23.0",
NumberStyles.AllowDecimalPoint,
CultureInfo.InvariantCulture,
out v);
v will hold the value 23 and wasParsedOK will be true.
You can't assume that the version string is going to be integral, or even decimal. A browser could perfectly report 7.0b as its version. None of int, float, decimal or System.Version can represent this.
If you're only concerned about the major and minor version numbers, you can use the MajorVersion and MinorVersion properties of your Browser object, assuming it is of type HttpBrowserCapabilities. The framework has done the parsing for you, so it should be reliable.
It is giving false because 23.0 is not an int, So you can try with decimal,double or float.
decimal v = 0;
string version = "23.0";
Decimal.TryParse(version, out v);
It's been almost 2 years and no one has answered this correctly. The question is simple, "Why is it returning false?"
This question has already been answered, simply because your string is not an Integer, but is a Double or Decimal. By design, TryParse will try to get the EXACT match of the type integer from your string, if not it will return false, and your string ("23.0") is not an exact match.
Now if you're trying to find a solution in converting your version string to a number, What you can do is filter out the non-numeric, excluding 1 dot (.), in the string, then convert what's left to decimal/double. After this conversion you can then try converting it integer. Since you already converted your stirng to double/decimal, you can no longer use TryParse because the parameter needs to be in string format. You can then use Convert.ToInt32 inside a Try block.

casting ExecuteScalar() result c#

why would this work
int collectionCharge = (int)cmdCheck.ExecuteScalar();
but this produces an exception
double collectionCharge = (double)cmdCheck.ExecuteScalar();
System.InvalidCastException: Specified cast is not valid.
why would it not be valid?
EDIT
I am trying to simply return a single result from a query, that gets the price of some freight. So I can't turn this into an int because it must have decimals, hence trying to cast to a double. I am still learning asp.net so if there's a better way to achieve this, please do point me in the right direction :)
EDIT 2
the full code with SQL...
using (SqlCommand cmdCheck = new SqlCommand("SELECT FREIGHT_PRICE FROM FREIGHT_QUOTER_BELNL_NEW WHERE CUSTOMER_NO = #CUSTOMER_NO AND COUNTRY = #COUNTRY AND ROUND(WEIGHT_FROM,0) < #WEIGHT AND ROUND(WEIGHT_TO,0) >= #WEIGHT AND SHIPVIA = '48';", connection))
{
double collectionCharge = (double)cmdCheck.ExecuteScalar();
FreightAmount = collectionCharge;
}
The problem here is that ExecuteScalar is returning an int which is boxed into an object. In order to convert to a double you must first unbox to an int then convert to a double
double collectionCharge = (double)(int)cmdCheck.ExecuteScalar();
Use the Convert.ToXXX to avoid invalid cast exceptions.
I.E
collectionCharge=Convert.ToDouble(cmdCheck.ExecuteScalar());
As it appears that ExecuteScalar returns an Object so the code:
double collectionCharge = (double)cmdCheck.ExecuteScalar();
Could still fail
With thanks to #DJKRAZE.
I updated my query to SELECT CASE(FREIGHT_PRICE AS FLOAT) which now works with the (double) cast.
double collectionCharge = (double)cmdCheck.ExecuteScalar();
After reading all answers, I had a case of receiving the Decimal values indeed, and the solution was easy!
I just declared the function as string and received the Decimal value as string!
public static string Sals_AccountExpensesGetSums(int accountID)
{
SqlParameterHelper sph = new
SqlParameterHelper(ConnectionString.GetWriteConnectionString(),
"sals_AccountExpenses_GetAllSums", 1);
sph.DefineSqlParameter("#AccountID", SqlDbType.Int, ParameterDirection.Input, accountID);
string res = sph.ExecuteScalar().ToString();
return res;
}
and in the business layer i changed the result to double!
public static decimal GetAccountExpensesSums(int accountId)
{
string res = "";
decimal sums = 0;
res = DBAccount.Sals_AccountExpensesGetSums(accountId);
// check so we will not have exception
if ( res != "")
sums = Convert.ToDecimal(res);
return sums;
}
and the result was perfect as needed: 889678.70
I would recommend using this code:
object o = c.ExecuteScalar();
if (o != null)
{
int x = Int32.Parse(o.ToString());
}
This does two things. First it makes sure that your c.ExecuteScalar() isn't returning null If it did so and you tried to cast, you'd have problems.
Second, it makes casting much simpler because it can be applied to pretty much all cases when reading from a query.
The object becomes a string. If you want it as a string, you're done.
If you want it as a boolean, check to see if that string.Equals("true")
If you want it as an int, Int32.Parse(string);
if you want it as a long, Int64.Parse(string);
Basically, you won't have to worry about fully understanding overloading/explicit conversion.

Error: Specified cast is not valid while converting decimal to double

I have a function as under
private double RoundOff(object value)
{
return Math.Round((double)value, 2);
}
And I am invoking it as under
decimal dec = 32.464762931906M;
var res = RoundOff(dec);
I am gettingthe below error
Specified cast is not valid
What is the mistake?
Thanks
Casting the object to double will attempt to unbox the object as a double, but the boxed object is a decimal. You need to convert it to a double after first unboxing it. Then you perform the rounding:
Math.Round((double)(decimal)value, 2);
The other answers are correct in terms of getting something that will run - but I wouldn't recommend using them.
You should almost never convert between decimal and double. If you want to use a decimal, you should use Math.Round(decimal). Don't convert a decimal to double and round that - there could easily be nasty situations where that loses information.
Pick the right representation and stick with it. Oh, and redesign RoundOff to not take object. By all means have one overload for double and one for decimal, but give them appropriate parameter types.
As an alternative to John's answer, if you want to use other number types than just decimal, you could use this code;
private double RoundOff(object value)
{
return Math.Round(Convert.ToDouble(value), 2);
}

Categories

Resources