I am getting a System.InvalidCastException at runtime with this code:
inf.Country = (Country)(int)rdr["Country"];
Model class:
public class BasicInfo
{
.....
public Gender Gender { get; set; }
public Country Country { get; set; }
}
public enum Gender
{
Male,
Female
}
public enum Country
{
Australia,
Bangladesh,
England,
France,
Usa
}
DbConnect class: the method return the entities list and it will pass through the controller's view.
usp_GetAllStudentData is a stored procedure that returns the list of records.
public List<BasicInfo> SelectStudent()
{
ConnectionString();//Contain Connection string
List<BasicInfo> entities = new List<BasicInfo>();
SqlCommand cmd = new SqlCommand("usp_GetAllStudentData", conn);
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while(rdr.Read())
{
BasicInfo inf = new BasicInfo();
inf.FirstName = (string)rdr["FirstName"];
.....//other required value are assigned to class members.
//inf.Gender = (Gender)(int)rdr["Gender"];
inf.Country = (Country)(int)rdr["Country"]; // Getting run time exception here
entities.Add(inf);
}
return entities;
}
How the data is stored in the database
Can you guys let me know what is the best method to cast an enum value?
Or let me know if there is any alternative way to fix this issue.
Table Design
If your database field contains a NULL value then the result of your code is the Invalid Cast Exception
For example
object x = DbNull.Value; // A null value on the db is represented by DbNull.Value
inf.Country = (Country)(int)x; // Gives the Invalid Cast Exception
How to fix depends on what you want to do with null values. If you don't allow null values for countries then you should revise your code that accepts an invalid input and block these inputs (and not forget to set the Country field to NOT allow NULL values on the database table)
If you accept a null value then I suggest to add another entry to your country enum
public enum Country
{
Australia = 0,
Bangladesh,
England,
France,
Usa,
// <=== new countries should be added here....
Undefined = 9999
}
and change your reading code to
int ordinal = rdr.GetOrdinal("Country");
inf.Country = rdr.IsDBNull(ordinal) ? Country.Undefined
: (Country)(int)rdr["Country"];
From your comments it seems that you have stored the numeric value of the enum in a varchar column transforming your number in a string
If you want to convert back this string to the appropriate enum value then you should use Enum.TryParse, but the conversion back is not as simple as it seems.
So if you want to still check for null values then:
int ordinal = rdr.GetOrdinal("Country");
// Check for null value....
if(rdr.IsDBNull(ordinal))
inf.Country = Country.Undefined;
else
{
// OK, not null, but what if it is "ABC"??
if(!Enum.TryParse(rdr["Country"].ToString(), out inf.Country))
inf.Country = Country.Undefined;
// OK, but what if it is a number not defined in the coutry enum (IE "88")
if(!Enum.IsDefined(typeof(Country), inf.Country))
inf.Country = Country.Undefined;
}
As you can see, if there isn't a specific reason then I suggest to store the enum value as an integer and not as a string. This allow more flexibility in your code and in future changes to this variable.
try this
if (rdr["Country"]!=DBNull.Value)
{
inf.Country =(Country)Enum.ToObject(typeof(Country) , rdr["Country"].ToString());
}
Related
I got a problem where I can't read the data from my database correctly.
To give you an example, I got the important value that is in the database 6.69879289850025E-06, but I read 6.0 (which is not accurate since it's suppose to be way smaller) in the C# program.
Something similar happen to ImportantValue2 where the value that is in the database is -0,000158976621370616 and in my C# program I get 0,0.
public double ImportantValue1 { get; set; }
public double ImportantValue2 { get; set; }
public string Note { get; set; }
public MyObject(SQLiteDataReader reader)
{
ImportantValue1 = Convert.ToDouble(reader["important_value_1"]); //Value in the database is REAL
ImportantValue2 = Convert.ToDouble(reader["important_value_2"]);//Value in the database is REAL
Note = reader["note"].ToString(); //Value in the database is TEXT
}
Update
And this is how I call it.
using (SQLiteConnection c = new SQLiteConnection(connection))
{
c.Open();
using (SQLiteCommand cmd = new SQLiteCommand(sqlCommand, c))
{
using (SQLiteDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
objectFromBD = new MyObject(reader);
}
}
}
}
And the SQLite code
CREATE TABLE "table"(
"id" INTEGER,
"important_value_1" REAL NOT NULL,
"important_value_2" REAL NOT NULL,
"note" TEXT NOT NULL,
PRIMARY KEY ("id" AUTOINCREMENT)
);
Thank you for your help!
reader["important_value_1"] will return index which column exists in your SQL script instead of your expectation value.
reader["important_value_1"] will get the value of the specified column.
You can try to use reader["important_value_1"] in reader.GetDouble function to read your data from columns.
ImportantValue1 = reader.GetDouble(reader["important_value_1"])
ImportantValue2 = reader.GetDouble(reader["important_value_2"])
SqliteDataReader.Item[] Property
Note
You might need to use reader.Read() let the reader point to read the next row if you want.
while (reader.Read()){
//... read all rows from your db
}
Here is a temporary solution I got, but that is not efficient.
I saw that I can read a string with the reader, but I couldn't do it with a double. So I used reader.GetString(rowValue); and than I converted the string to a double using the fonction below.
public double StringToDoubleWithNotation(string value)
{
return Convert.ToDouble(Decimal.Parse(value, NumberStyles.AllowExponent | NumberStyles.AllowDecimalPoint));
}
Now everything is fine, but I would prefer to see a better solution since doing 3 conversion is not that efficient.
I'm trying to update my table with this LINQ query
public void updateProduct(
int selectedIDToUpdate,
string prodNAMEToUp,
double prodPriceToUp,
string prodTYPEToUp,
int prodMANUToUp,
int prodCODEToUp)
{
DataClassesLINQEPOSDataContext dcld = new DataClassesLINQEPOSDataContext();
TBLPRODUCT tblprod = (from prod in dcld.TBLPRODUCTs
where prod.product_id == selectedIDToUpdate
select prod).First();
tblprod.product_name = prodNAMEToUp;
tblprod.product_price = prodPriceToUp;
tblprod.product_type = prodTYPEToUp;
tblprod.product_manufacturer = prodMANUToUp;
tblprod.product_code = prodCODEToUp;
dcld.SubmitChanges();
}
and then when I start to run the program I have this error
"InvalidCastException was unhandled"
"Specified cast is not valid."
Sorry I cant post image because I dont have enough reputation "points" :(
this is the control to pass the parameter on my class.
private void btnSaveToUpdate_Click(object sender, EventArgs e)
{
if (txtNameToUpdate.Text != "" ||
txtPriceToUpdate.Text != "" ||
txtTypeToUpdate.Text != "" ||
txtCodeToUpdate.Text != "")
{
Connection_Products update = new Connection_Products();
int selctedID = selectedIDToUpdate;
string prodNAMEToUp = txtNameToUpdate.Text;
double prodPriceToUp = double.Parse(txtPriceToUpdate.Text);
string prodTYPEToUp = txtTypeToUpdate.Text;
int prodMANUToUp = Convert.ToInt32(cmbManufacturerToUpdate.SelectedValue);
int prodCODEToUp = Convert.ToInt32(txtCodeToUpdate.Text);
update.updateProduct(selctedID, prodNAMEToUp, prodPriceToUp,
prodTYPEToUp, prodMANUToUp, prodCODEToUp);
}
else
{
MessageBox.Show("Error");
}
}
You most likely have some datatype mismatch between the values that you are trying to store and the data types of the columns in the database. This would be in one of the numeric columns.
If the prodPriceToUp column uses the money data type, this maps to a decimal type in Linq2Sql. You are trying to cast the double for the input parameter to decimal, which may be causing this issue. Try converting prodPriceToUp to a decimal before saving it.
I guess you are missing something in type mapping between updateProduct params and properties in tblprod. Please check here you are using correct types
This is because one of the following is trying to cast into an invalid type:
tblprod.product_name = prodNAMEToUp;
tblprod.product_price = prodPriceToUp;
tblprod.product_type = prodTYPEToUp;
tblprod.product_manufacturer = prodMANUToUp;
tblprod.product_code = prodCODEToUp;
Check for each of the these that the type of the left side is the same as the type of the right side. for example ensure that "tblprod.product_name" is a string property as you are trying to save a string to that property.
It is also possible that in your LINQ query, the where clause may have this problem, ensure that "prod.product_id" is an integer and not something else like a long or a short.
if these are all ok and you are still getting the exception then you will need to tell use what line is throwing the exception, and give use the details of the structure of tblprod;
I am trying to insert a DateTime value in sqlserver using linq. The DateTime value in the csharp side may be null. The corresponding field in sqlserver is a nullable datetime field. Following is my code:
using (var dataContext = GetDataContext())
{
DateTime dateTime;
var combinedWorkBasket = new CombinedWorkBasket()
{
FirstName = combinedWorkbasketData.FirstName,
LastName = combinedWorkbasketData.LastName,
Address1 = combinedWorkbasketData.Address1,
RetirementDate = Convert.ToDateTime(combinedWorkbasketData.RetirementDate),
};
dataContext.CombinedWorkBaskets.InsertOnSubmit(combinedWorkBasket);
dataContext.SubmitChanges();
}
When combinedWorkbasketData.RetirementDate happens to be null, which is a string value, which could be a valid date or null, then sqlserver throws error saying the date should be within range. When combinedWorkbasketData.RetirementDate happens to be null, Convert.ToDateTime(combinedWorkbasketData.RetirementDate) translates to some invalide data value. I tried the following, still same issue.
RetirementDate = DateTime.TryParse(combinedWorkbasketData.RetirementDate, out temp) ? Convert.ToDateTime(combinedWorkbasketData.RetirementDate) : Convert.ToDateTime(null)
I simply want to accomplish the following: When combinedWorkbasketData.RetirementDate is a valid date insert RetirementDate, otherwise don't insert it but insert other values such as Firstname etc
Thanks
You might want to use a nullable data type, but this helps only if your database permits null values in the RetirementDate column. In addition, you must make the RetirementDate field in class CombinedWorkBasket nullable, too.
using (var dataContext = GetDataContext())
{
DateTime? dateTime;
var combinedWorkBasket = new CombinedWorkBasket()
{
FirstName = combinedWorkbasketData.FirstName,
LastName = combinedWorkbasketData.LastName,
Address1 = combinedWorkbasketData.Address1,
RetirementDate = combinedWorkbasketData.RetirementDate != null ?
Convert.ToDateTime(combinedWorkbasketData.RetirementDate) : null;
};
dataContext.CombinedWorkBaskets.InsertOnSubmit(combinedWorkBasket);
dataContext.SubmitChanges();
}
The problem is that datetime does not holds null value but it holds minimum time i.e. some thing like this. '1/1/0001 12:00:00 AM'.
Instead of directly passing the date time try using
DateTime.MinValue== Convert.ToDateTime(combinedWorkbasketData.RetirementDate)?Null:Convert.ToDateTime(combinedWorkbasketData.RetirementDate)
I have not tested the code use it as reference u might be needing some refinement.
I think RetirementDate must be of nullable type for Entity framework to insert DBNull.
So make it like
public class CombinedWorkBasket
{
// other fields
public DateTime? RetirementDate { get; set; }
}
Then try assigning Null as per logic with associated column as "Allow Null" in database.
Hopefully it will insert null.
Howsit!
I encounter an error when i get a null value in my datareader.
public List<Complaint> View_all_complaints()
{
csDAL objdal= new csDAL();
List<Complaint> oblcomplist=new List<Complaint>();
using( IDataReader dr=objdal.executespreturndr("View_all_complaints"))
{
while (dr.Read())
{
Complaint objcomp= new Complaint();
populate_reader(dr,objcomp);
oblcomplist.Add(objcomp);
}
}
return oblcomplist;
}
public void populate_reader(IDataReader dr, Complaint objcomp)
{
objcomp.ref_num = dr.GetString(0);
objcomp.type = dr.GetString(1);
objcomp.desc = dr.GetString(2);
objcomp.date = dr.GetDateTime(3);
objcomp.housenum = dr.GetInt32(4);
objcomp.streetnum = dr.GetInt32(5);
objcomp.status = dr.GetString(6);
objcomp.priority = dr.GetString(7);
objcomp.cid = dr.GetInt32(8);
if (!dr.IsDBNull(9))
{
objcomp.resolved_date = dr.GetDateTime(9);
}
}
in sql resolved date allows null values, this is so because only when a complaint has been resolved , it must reflect that date otherwise it should be null.
if dr.getdatetime(9) is null then it must just set a string saying "Not Resolved"
please help!
You haven't shown what your Complaint type looks like, but basically you'll want to make sure that its resolved_date is of type DateTime? aka Nullable<DateTime>. That allows you to model a missing value elegantly.
As for displaying it - you haven't shown anything about where you display the data, but you'd want something like:
string text = complaint.ResolvedDate.HasValue ? complaint.ResolvedDate.ToString()
: "Not Resolved";
(I've changed this to use a property with the idiomatic name at the same time...)
IDataReader has a "IsDBNull" method, that should be called before calling GetXXX(), in case your value is not nullable.
For example:
objcomp.date = dr.GetDateTime(3);
should be:
objcomp.date = dr.IsDBNull(3) ? DateTime.MinValue : dr.GetDateTime(3);
First, let me tell you what error I am getting.
'DDLTesttoAppear' has a SelectedIndex which is invalid because it
does not exist in the list of items. Parameter name: value
I have many enums in my project, Here two enums are related two this question.
This Two enums are
public enum Gender
{
NA = 0, Male = 1, Female = 2
}
and
public enum NumberOfAdmissionTest
{
NA = 0, First = 1, Second = 2, Third = 3, Fourth =4
}
In UI page I have two DDls they are like
DDLGender.DataSource = Enum.GetNames(typeof(Gender));
DDLGender.DataBind();
DDLTestApearnce.DataSource = Enum.GetNames(typeof(NumberOfAdmissionTest));
DDLTestApearnce.DataBind();
This fields can be inserted as null into the database. Therefore, while returning the record I am using a null hander function
where the line of code to execute is that
candidateEntity.CandidateGender = nullHandler.GetInt32(CANDIDATE_GENDER);
candidateEntity.TestToAppear = nullHandler.GetInt32(TEST_TO_APPEAR);
public int GetInt32(String sFieldName)
{
return (_reader[sFieldName] == DBNull.Value) ? 0 : _reader.GetInt32(_reader.GetOrdinal(sFieldName));
}
After retrieving the record, I am binding this with two ddls like
DDLGender.SelectedIndex = candidateEntity.CandidateGender;
DDLTesttoAppear.SelectedIndex = candidateEntity.TestToAppear;
Now, the interesting or confusing, whatever you say, part of this problem is that for gender, it's not generating any error, but for test appearance it's generating the error.
You are binding DDLTestApearnce in your sample, but are getting the error (and setting the selected value) on DDLTesttoAppear.