简体   繁体   中英

InvalidCastException, fetching enum value from SqlDataReader in ASP.NET MVC

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());
 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM