Related
I'm using a SQLdatareader to build POCOs from a database. The code works except when it encounters a null value in the database. For example, if the FirstName column in the database contains a null value, an exception is thrown.
employee.FirstName = sqlreader.GetString(indexFirstName);
What is the best way to handle null values in this situation?
You need to check for IsDBNull:
if(!SqlReader.IsDBNull(indexFirstName))
{
employee.FirstName = sqlreader.GetString(indexFirstName);
}
That's your only reliable way to detect and handle this situation.
I wrapped those things into extension methods and tend to return a default value if the column is indeed null:
public static string SafeGetString(this SqlDataReader reader, int colIndex)
{
if(!reader.IsDBNull(colIndex))
return reader.GetString(colIndex);
return string.Empty;
}
Now you can call it like this:
employee.FirstName = SqlReader.SafeGetString(indexFirstName);
and you'll never have to worry about an exception or a null value again.
You should use the as operator combined with the ?? operator for default values. Value types will need to be read as nullable and given a default.
employee.FirstName = sqlreader[indexFirstName] as string;
employee.Age = sqlreader[indexAge] as int? ?? default(int);
The as operator handles the casting including the check for DBNull.
employee.FirstName = sqlreader[indexFirstName] as string;
For integers, if you cast to a nullable int, you can use GetValueOrDefault()
employee.Age = (sqlreader[indexAge] as int?).GetValueOrDefault();
or the null-coalescing operator (??).
employee.Age = (sqlreader[indexAge] as int?) ?? 0;
IsDbNull(int) is usually much slower than using methods like GetSqlDateTime and then comparing to DBNull.Value. Try these extension methods for SqlDataReader.
public static T Def<T>(this SqlDataReader r, int ord)
{
var t = r.GetSqlValue(ord);
if (t == DBNull.Value) return default(T);
return ((INullable)t).IsNull ? default(T) : (T)t;
}
public static T? Val<T>(this SqlDataReader r, int ord) where T:struct
{
var t = r.GetSqlValue(ord);
if (t == DBNull.Value) return null;
return ((INullable)t).IsNull ? (T?)null : (T)t;
}
public static T Ref<T>(this SqlDataReader r, int ord) where T : class
{
var t = r.GetSqlValue(ord);
if (t == DBNull.Value) return null;
return ((INullable)t).IsNull ? null : (T)t;
}
Use them like this:
var dd = r.Val<DateTime>(ords[4]);
var ii = r.Def<int>(ords[0]);
int nn = r.Def<int>(ords[0]);
if(reader.IsDBNull(ColumnIndex)) {// logic} works as many answers says.
And I want to mention if you working with column names, just comparing types may be more comfortable.
if(reader["TeacherImage"].GetType() == typeof(DBNull)) { //logic }
I don't think there's a NULL column value, when rows are returned within a datareader using the column name.
If you do datareader["columnName"].ToString(); it will always give you a value that can be a empty string (String.Empty if you need to compare).
I would use the following and wouldn't worry too much:
employee.FirstName = sqlreader["columnNameForFirstName"].ToString();
You can write a Generic function to check Null and include default value when it is NULL. Call this when reading Datareader
public T CheckNull<T>(object obj)
{
return (obj == DBNull.Value ? default(T) : (T)obj);
}
When reading the Datareader use
while (dr.Read())
{
tblBPN_InTrRecon Bpn = new tblBPN_InTrRecon();
Bpn.BPN_Date = CheckNull<DateTime?>(dr["BPN_Date"]);
Bpn.Cust_Backorder_Qty = CheckNull<int?>(dr["Cust_Backorder_Qty"]);
Bpn.Cust_Min = CheckNull<int?>(dr["Cust_Min"]);
}
One way to do it is to check for db nulls:
employee.FirstName = (sqlreader.IsDBNull(indexFirstName)
? ""
: sqlreader.GetString(indexFirstName));
This Solution is less vendor-dependent and works with an SQL, OleDB, and MySQL Reader:
public static string GetStringSafe(this IDataReader reader, int colIndex)
{
return GetStringSafe(reader, colIndex, string.Empty);
}
public static string GetStringSafe(this IDataReader reader, int colIndex, string defaultValue)
{
if (!reader.IsDBNull(colIndex))
return reader.GetString(colIndex);
else
return defaultValue;
}
public static string GetStringSafe(this IDataReader reader, string indexName)
{
return GetStringSafe(reader, reader.GetOrdinal(indexName));
}
public static string GetStringSafe(this IDataReader reader, string indexName, string defaultValue)
{
return GetStringSafe(reader, reader.GetOrdinal(indexName), defaultValue);
}
What I tend to do is replace the null values in the SELECT statement with something appropriate.
SELECT ISNULL(firstname, '') FROM people
Here I replace every null with a blank string. Your code won't throw in error in that case.
By influencing from getpsyched's answer, I created a generic method which checks column value by its name
public static T SafeGet<T>(this System.Data.SqlClient.SqlDataReader reader, string nameOfColumn)
{
var indexOfColumn = reader.GetOrdinal(nameOfColumn);
return reader.IsDBNull(indexOfColumn) ? default(T) : reader.GetFieldValue<T>(indexOfColumn);
}
Usage:
var myVariable = SafeGet<string>(reader, "NameOfColumn")
Check sqlreader.IsDBNull(indexFirstName) before you try to read it.
As an addition to the answer by marc_s, you can use a more generic extension method to get values from the SqlDataReader:
public static T SafeGet<T>(this SqlDataReader reader, int col)
{
return reader.IsDBNull(col) ? default(T) : reader.GetFieldValue<T>(col);
}
how to about creating helper methods
For String
private static string MyStringConverter(object o)
{
if (o == DBNull.Value || o == null)
return "";
return o.ToString();
}
Usage
MyStringConverter(read["indexStringValue"])
For Int
private static int MyIntonverter(object o)
{
if (o == DBNull.Value || o == null)
return 0;
return Convert.ToInt32(o);
}
Usage
MyIntonverter(read["indexIntValue"])
For Date
private static DateTime? MyDateConverter(object o)
{
return (o == DBNull.Value || o == null) ? (DateTime?)null : Convert.ToDateTime(o);
}
Usage
MyDateConverter(read["indexDateValue"])
Note: for DateTime declare varialbe as
DateTime? variable;
None of these was quite what i wanted:
public static T GetFieldValueOrDefault<T>(this SqlDataReader reader, string name)
{
int index = reader.GetOrdinal(name);
T value = reader.IsDBNull(index) ? default(T) : reader.GetFieldValue<T>(index);
return value;
}
I think you would want to use:
SqlReader.IsDBNull(indexFirstName)
We use a series of static methods to pull all of the values out of our data readers. So in this case we'd be calling DBUtils.GetString(sqlreader(indexFirstName)) The benefit of creating static/shared methods is that you don't have to do the same checks over and over and over...
The static method(s) would contain code to check for nulls (see other answers on this page).
You may use the conditional operator:
employee.FirstName = sqlreader["indexFirstName"] != DBNull.Value ? sqlreader[indexFirstName].ToString() : "";
There are a lot of answers here with useful info (and some wrong info) spread about, I'd like to bring it all together.
The short answer to the question is to check for DBNull - almost everyone agrees on this bit :)
Rather than using a helper method to read nullable values per SQL data type a generic method allows us to address this with a lot less code. However, you can't have a single generic method for both nullable value types and reference types, this is discussed at length in
Nullable type as a generic parameter possible? and C# generic type constraint for everything nullable.
So, following on from the answers from #ZXX and #getpsyched we end up with this, 2 methods for getting nullable values and I've added a 3rd for non-null values (it completes the set based on method naming).
public static T? GetNullableValueType<T>(this SqlDataReader sqlDataReader, string columnName) where T : struct
{
int columnOrdinal = sqlDataReader.GetOrdinal(columnName);
return sqlDataReader.IsDBNull(columnOrdinal) ? (T?)null : sqlDataReader.GetFieldValue<T>(columnOrdinal);
}
public static T GetNullableReferenceType<T>(this SqlDataReader sqlDataReader, string columnName) where T : class
{
int columnOrdinal = sqlDataReader.GetOrdinal(columnName);
return sqlDataReader.IsDBNull(columnOrdinal) ? null : sqlDataReader.GetFieldValue<T>(columnOrdinal);
}
public static T GetNonNullValue<T>(this SqlDataReader sqlDataReader, string columnName)
{
int columnOrdinal = sqlDataReader.GetOrdinal(columnName);
return sqlDataReader.GetFieldValue<T>(columnOrdinal);
}
I usually use column names, alter these if you use column indexes. Based on these method names I can tell whether I'm expecting the data to be nullable or not, quite useful when looking at code written a long time ago.
Tips;
Not having nullable columns in the database avoids this issue. If you
have control over the database then columns should be non-null by
default and only nullable where necessary.
Don't cast database values
with the C# 'as' operator because if the cast is wrong it will
silently return null.
Using a default value expression will change
database nulls to non-null values for value types like int, datetime,
bit etc.
Lastly, whilst testing the above methods across all SQL Server data types I discovered you can't directly get a char[] from a SqlDataReader, if you want a char[] you will have to get a string and use ToCharArray().
I am using the code listed below to handle null cells in an Excel sheet that is read in to a datatable.
if (!reader.IsDBNull(2))
{
row["Oracle"] = (string)reader[2];
}
private static void Render(IList<ListData> list, IDataReader reader)
{
while (reader.Read())
{
listData.DownUrl = (reader.GetSchemaTable().Columns["DownUrl"] != null) ? Convert.ToString(reader["DownUrl"]) : null;
//没有这一列时,让其等于null
list.Add(listData);
}
reader.Close();
}
and / or use ternary operator with assignment:
employee.FirstName = rdr.IsDBNull(indexFirstName))?
String.Empty: rdr.GetString(indexFirstName);
replace the default (when null) value as appropriate for each property type...
This method is dependent on indexFirstName which should be the zero-based column ordinal.
if(!sqlReader.IsDBNull(indexFirstName))
{
employee.FirstName = sqlreader.GetString(indexFirstName);
}
If you don't know the column index but wan't to check a name you can use this extension method instead:
public static class DataRecordExtensions
{
public static bool HasColumn(this IDataRecord dr, string columnName)
{
for (int i=0; i < dr.FieldCount; i++)
{
if (dr.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase))
return true;
}
return false;
}
}
And use the method like this:
if(sqlReader.HasColumn("FirstName"))
{
employee.FirstName = sqlreader["FirstName"];
}
Old question but maybe someone still need an answer
in real i worked around this issue like that
For int :
public static object GatDataInt(string Query, string Column)
{
SqlConnection DBConn = new SqlConnection(ConnectionString);
if (DBConn.State == ConnectionState.Closed)
DBConn.Open();
SqlCommand CMD = new SqlCommand(Query, DBConn);
SqlDataReader RDR = CMD.ExecuteReader();
if (RDR.Read())
{
var Result = RDR[Column];
RDR.Close();
DBConn.Close();
return Result;
}
return 0;
}
the same for string just return "" instead of 0 as "" is empty string
so you can use it like
int TotalPoints = GatDataInt(QueryToGetTotalPoints, TotalPointColumn) as int?;
and
string Email = GatDatastring(QueryToGetEmail, EmailColumn) as string;
very flexible so you can insert any query to read any column and it'll never return with error
Here is helper class which others can use if they need based on #marc_s answer:
public static class SQLDataReaderExtensions
{
public static int SafeGetInt(this SqlDataReader dataReader, string fieldName)
{
int fieldIndex = dataReader.GetOrdinal(fieldName);
return dataReader.IsDBNull(fieldIndex) ? 0 : dataReader.GetInt32(fieldIndex);
}
public static int? SafeGetNullableInt(this SqlDataReader dataReader, string fieldName)
{
int fieldIndex = dataReader.GetOrdinal(fieldName);
return dataReader.GetValue(fieldIndex) as int?;
}
public static string SafeGetString(this SqlDataReader dataReader, string fieldName)
{
int fieldIndex = dataReader.GetOrdinal(fieldName);
return dataReader.IsDBNull(fieldIndex) ? string.Empty : dataReader.GetString(fieldIndex);
}
public static DateTime? SafeGetNullableDateTime(this SqlDataReader dataReader, string fieldName)
{
int fieldIndex = dataReader.GetOrdinal(fieldName);
return dataReader.GetValue(fieldIndex) as DateTime?;
}
public static bool SafeGetBoolean(this SqlDataReader dataReader, string fieldName)
{
return SafeGetBoolean(dataReader, fieldName, false);
}
public static bool SafeGetBoolean(this SqlDataReader dataReader, string fieldName, bool defaultValue)
{
int fieldIndex = dataReader.GetOrdinal(fieldName);
return dataReader.IsDBNull(fieldIndex) ? defaultValue : dataReader.GetBoolean(fieldIndex);
}
}
in c# 7.0 we can do :
var a = reader["ERateCode"] as string;
var b = reader["ERateLift"] as int?;
var c = reader["Id"] as int?;
so it will keep null value if it is.
I did my best to reimplement the Field method from DataTable. https://learn.microsoft.com/en-us/dotnet/api/system.data.datarowextensions.field
It will throw if you try to convert a DBNull.Value to a non-nullable type. Otherwise it will convert DBNull.Value to null.
I haven't fully tested it.
public static T Field<T>(this SqlDataReader sqlDataReader, string columnName)
{
int columnIndex = sqlDataReader.GetOrdinal(columnName);
if (sqlDataReader.IsDBNull(columnIndex))
{
if (default(T) != null)
{
throw new InvalidCastException("Cannot convert DBNULL value to type " + typeof(T).Name);
}
else
{
return default(T);
}
}
else
{
return sqlDataReader.GetFieldValue<T>(columnIndex);
}
}
Usage:
string fname = sqlDataReader.Field<string>("FirstName");
int? age = sqlDataReader.Field<int?>("Age");
int yearsOfExperience = sqlDataReader.Field<int?>("YearsEx") ?? 0;
Convert handles DbNull sensibly.
employee.FirstName = Convert.ToString(sqlreader.GetValue(indexFirstName));
neat one-liner:
while (dataReader.Read())
{
employee.FirstName = (!dataReader.IsDBNull(dataReader.GetOrdinal("FirstName"))) ? dataReader["FirstName"].ToString() : "";
}
you can ever check for this as well
if(null !=x && x.HasRows)
{ ....}
I'm using a SQLdatareader to build POCOs from a database. The code works except when it encounters a null value in the database. For example, if the FirstName column in the database contains a null value, an exception is thrown.
employee.FirstName = sqlreader.GetString(indexFirstName);
What is the best way to handle null values in this situation?
You need to check for IsDBNull:
if(!SqlReader.IsDBNull(indexFirstName))
{
employee.FirstName = sqlreader.GetString(indexFirstName);
}
That's your only reliable way to detect and handle this situation.
I wrapped those things into extension methods and tend to return a default value if the column is indeed null:
public static string SafeGetString(this SqlDataReader reader, int colIndex)
{
if(!reader.IsDBNull(colIndex))
return reader.GetString(colIndex);
return string.Empty;
}
Now you can call it like this:
employee.FirstName = SqlReader.SafeGetString(indexFirstName);
and you'll never have to worry about an exception or a null value again.
You should use the as operator combined with the ?? operator for default values. Value types will need to be read as nullable and given a default.
employee.FirstName = sqlreader[indexFirstName] as string;
employee.Age = sqlreader[indexAge] as int? ?? default(int);
The as operator handles the casting including the check for DBNull.
employee.FirstName = sqlreader[indexFirstName] as string;
For integers, if you cast to a nullable int, you can use GetValueOrDefault()
employee.Age = (sqlreader[indexAge] as int?).GetValueOrDefault();
or the null-coalescing operator (??).
employee.Age = (sqlreader[indexAge] as int?) ?? 0;
IsDbNull(int) is usually much slower than using methods like GetSqlDateTime and then comparing to DBNull.Value. Try these extension methods for SqlDataReader.
public static T Def<T>(this SqlDataReader r, int ord)
{
var t = r.GetSqlValue(ord);
if (t == DBNull.Value) return default(T);
return ((INullable)t).IsNull ? default(T) : (T)t;
}
public static T? Val<T>(this SqlDataReader r, int ord) where T:struct
{
var t = r.GetSqlValue(ord);
if (t == DBNull.Value) return null;
return ((INullable)t).IsNull ? (T?)null : (T)t;
}
public static T Ref<T>(this SqlDataReader r, int ord) where T : class
{
var t = r.GetSqlValue(ord);
if (t == DBNull.Value) return null;
return ((INullable)t).IsNull ? null : (T)t;
}
Use them like this:
var dd = r.Val<DateTime>(ords[4]);
var ii = r.Def<int>(ords[0]);
int nn = r.Def<int>(ords[0]);
if(reader.IsDBNull(ColumnIndex)) {// logic} works as many answers says.
And I want to mention if you working with column names, just comparing types may be more comfortable.
if(reader["TeacherImage"].GetType() == typeof(DBNull)) { //logic }
I don't think there's a NULL column value, when rows are returned within a datareader using the column name.
If you do datareader["columnName"].ToString(); it will always give you a value that can be a empty string (String.Empty if you need to compare).
I would use the following and wouldn't worry too much:
employee.FirstName = sqlreader["columnNameForFirstName"].ToString();
You can write a Generic function to check Null and include default value when it is NULL. Call this when reading Datareader
public T CheckNull<T>(object obj)
{
return (obj == DBNull.Value ? default(T) : (T)obj);
}
When reading the Datareader use
while (dr.Read())
{
tblBPN_InTrRecon Bpn = new tblBPN_InTrRecon();
Bpn.BPN_Date = CheckNull<DateTime?>(dr["BPN_Date"]);
Bpn.Cust_Backorder_Qty = CheckNull<int?>(dr["Cust_Backorder_Qty"]);
Bpn.Cust_Min = CheckNull<int?>(dr["Cust_Min"]);
}
One way to do it is to check for db nulls:
employee.FirstName = (sqlreader.IsDBNull(indexFirstName)
? ""
: sqlreader.GetString(indexFirstName));
This Solution is less vendor-dependent and works with an SQL, OleDB, and MySQL Reader:
public static string GetStringSafe(this IDataReader reader, int colIndex)
{
return GetStringSafe(reader, colIndex, string.Empty);
}
public static string GetStringSafe(this IDataReader reader, int colIndex, string defaultValue)
{
if (!reader.IsDBNull(colIndex))
return reader.GetString(colIndex);
else
return defaultValue;
}
public static string GetStringSafe(this IDataReader reader, string indexName)
{
return GetStringSafe(reader, reader.GetOrdinal(indexName));
}
public static string GetStringSafe(this IDataReader reader, string indexName, string defaultValue)
{
return GetStringSafe(reader, reader.GetOrdinal(indexName), defaultValue);
}
What I tend to do is replace the null values in the SELECT statement with something appropriate.
SELECT ISNULL(firstname, '') FROM people
Here I replace every null with a blank string. Your code won't throw in error in that case.
By influencing from getpsyched's answer, I created a generic method which checks column value by its name
public static T SafeGet<T>(this System.Data.SqlClient.SqlDataReader reader, string nameOfColumn)
{
var indexOfColumn = reader.GetOrdinal(nameOfColumn);
return reader.IsDBNull(indexOfColumn) ? default(T) : reader.GetFieldValue<T>(indexOfColumn);
}
Usage:
var myVariable = SafeGet<string>(reader, "NameOfColumn")
Check sqlreader.IsDBNull(indexFirstName) before you try to read it.
As an addition to the answer by marc_s, you can use a more generic extension method to get values from the SqlDataReader:
public static T SafeGet<T>(this SqlDataReader reader, int col)
{
return reader.IsDBNull(col) ? default(T) : reader.GetFieldValue<T>(col);
}
how to about creating helper methods
For String
private static string MyStringConverter(object o)
{
if (o == DBNull.Value || o == null)
return "";
return o.ToString();
}
Usage
MyStringConverter(read["indexStringValue"])
For Int
private static int MyIntonverter(object o)
{
if (o == DBNull.Value || o == null)
return 0;
return Convert.ToInt32(o);
}
Usage
MyIntonverter(read["indexIntValue"])
For Date
private static DateTime? MyDateConverter(object o)
{
return (o == DBNull.Value || o == null) ? (DateTime?)null : Convert.ToDateTime(o);
}
Usage
MyDateConverter(read["indexDateValue"])
Note: for DateTime declare varialbe as
DateTime? variable;
None of these was quite what i wanted:
public static T GetFieldValueOrDefault<T>(this SqlDataReader reader, string name)
{
int index = reader.GetOrdinal(name);
T value = reader.IsDBNull(index) ? default(T) : reader.GetFieldValue<T>(index);
return value;
}
I think you would want to use:
SqlReader.IsDBNull(indexFirstName)
We use a series of static methods to pull all of the values out of our data readers. So in this case we'd be calling DBUtils.GetString(sqlreader(indexFirstName)) The benefit of creating static/shared methods is that you don't have to do the same checks over and over and over...
The static method(s) would contain code to check for nulls (see other answers on this page).
You may use the conditional operator:
employee.FirstName = sqlreader["indexFirstName"] != DBNull.Value ? sqlreader[indexFirstName].ToString() : "";
There are a lot of answers here with useful info (and some wrong info) spread about, I'd like to bring it all together.
The short answer to the question is to check for DBNull - almost everyone agrees on this bit :)
Rather than using a helper method to read nullable values per SQL data type a generic method allows us to address this with a lot less code. However, you can't have a single generic method for both nullable value types and reference types, this is discussed at length in
Nullable type as a generic parameter possible? and C# generic type constraint for everything nullable.
So, following on from the answers from #ZXX and #getpsyched we end up with this, 2 methods for getting nullable values and I've added a 3rd for non-null values (it completes the set based on method naming).
public static T? GetNullableValueType<T>(this SqlDataReader sqlDataReader, string columnName) where T : struct
{
int columnOrdinal = sqlDataReader.GetOrdinal(columnName);
return sqlDataReader.IsDBNull(columnOrdinal) ? (T?)null : sqlDataReader.GetFieldValue<T>(columnOrdinal);
}
public static T GetNullableReferenceType<T>(this SqlDataReader sqlDataReader, string columnName) where T : class
{
int columnOrdinal = sqlDataReader.GetOrdinal(columnName);
return sqlDataReader.IsDBNull(columnOrdinal) ? null : sqlDataReader.GetFieldValue<T>(columnOrdinal);
}
public static T GetNonNullValue<T>(this SqlDataReader sqlDataReader, string columnName)
{
int columnOrdinal = sqlDataReader.GetOrdinal(columnName);
return sqlDataReader.GetFieldValue<T>(columnOrdinal);
}
I usually use column names, alter these if you use column indexes. Based on these method names I can tell whether I'm expecting the data to be nullable or not, quite useful when looking at code written a long time ago.
Tips;
Not having nullable columns in the database avoids this issue. If you
have control over the database then columns should be non-null by
default and only nullable where necessary.
Don't cast database values
with the C# 'as' operator because if the cast is wrong it will
silently return null.
Using a default value expression will change
database nulls to non-null values for value types like int, datetime,
bit etc.
Lastly, whilst testing the above methods across all SQL Server data types I discovered you can't directly get a char[] from a SqlDataReader, if you want a char[] you will have to get a string and use ToCharArray().
I am using the code listed below to handle null cells in an Excel sheet that is read in to a datatable.
if (!reader.IsDBNull(2))
{
row["Oracle"] = (string)reader[2];
}
private static void Render(IList<ListData> list, IDataReader reader)
{
while (reader.Read())
{
listData.DownUrl = (reader.GetSchemaTable().Columns["DownUrl"] != null) ? Convert.ToString(reader["DownUrl"]) : null;
//没有这一列时,让其等于null
list.Add(listData);
}
reader.Close();
}
and / or use ternary operator with assignment:
employee.FirstName = rdr.IsDBNull(indexFirstName))?
String.Empty: rdr.GetString(indexFirstName);
replace the default (when null) value as appropriate for each property type...
This method is dependent on indexFirstName which should be the zero-based column ordinal.
if(!sqlReader.IsDBNull(indexFirstName))
{
employee.FirstName = sqlreader.GetString(indexFirstName);
}
If you don't know the column index but wan't to check a name you can use this extension method instead:
public static class DataRecordExtensions
{
public static bool HasColumn(this IDataRecord dr, string columnName)
{
for (int i=0; i < dr.FieldCount; i++)
{
if (dr.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase))
return true;
}
return false;
}
}
And use the method like this:
if(sqlReader.HasColumn("FirstName"))
{
employee.FirstName = sqlreader["FirstName"];
}
Old question but maybe someone still need an answer
in real i worked around this issue like that
For int :
public static object GatDataInt(string Query, string Column)
{
SqlConnection DBConn = new SqlConnection(ConnectionString);
if (DBConn.State == ConnectionState.Closed)
DBConn.Open();
SqlCommand CMD = new SqlCommand(Query, DBConn);
SqlDataReader RDR = CMD.ExecuteReader();
if (RDR.Read())
{
var Result = RDR[Column];
RDR.Close();
DBConn.Close();
return Result;
}
return 0;
}
the same for string just return "" instead of 0 as "" is empty string
so you can use it like
int TotalPoints = GatDataInt(QueryToGetTotalPoints, TotalPointColumn) as int?;
and
string Email = GatDatastring(QueryToGetEmail, EmailColumn) as string;
very flexible so you can insert any query to read any column and it'll never return with error
Here is helper class which others can use if they need based on #marc_s answer:
public static class SQLDataReaderExtensions
{
public static int SafeGetInt(this SqlDataReader dataReader, string fieldName)
{
int fieldIndex = dataReader.GetOrdinal(fieldName);
return dataReader.IsDBNull(fieldIndex) ? 0 : dataReader.GetInt32(fieldIndex);
}
public static int? SafeGetNullableInt(this SqlDataReader dataReader, string fieldName)
{
int fieldIndex = dataReader.GetOrdinal(fieldName);
return dataReader.GetValue(fieldIndex) as int?;
}
public static string SafeGetString(this SqlDataReader dataReader, string fieldName)
{
int fieldIndex = dataReader.GetOrdinal(fieldName);
return dataReader.IsDBNull(fieldIndex) ? string.Empty : dataReader.GetString(fieldIndex);
}
public static DateTime? SafeGetNullableDateTime(this SqlDataReader dataReader, string fieldName)
{
int fieldIndex = dataReader.GetOrdinal(fieldName);
return dataReader.GetValue(fieldIndex) as DateTime?;
}
public static bool SafeGetBoolean(this SqlDataReader dataReader, string fieldName)
{
return SafeGetBoolean(dataReader, fieldName, false);
}
public static bool SafeGetBoolean(this SqlDataReader dataReader, string fieldName, bool defaultValue)
{
int fieldIndex = dataReader.GetOrdinal(fieldName);
return dataReader.IsDBNull(fieldIndex) ? defaultValue : dataReader.GetBoolean(fieldIndex);
}
}
in c# 7.0 we can do :
var a = reader["ERateCode"] as string;
var b = reader["ERateLift"] as int?;
var c = reader["Id"] as int?;
so it will keep null value if it is.
I did my best to reimplement the Field method from DataTable. https://learn.microsoft.com/en-us/dotnet/api/system.data.datarowextensions.field
It will throw if you try to convert a DBNull.Value to a non-nullable type. Otherwise it will convert DBNull.Value to null.
I haven't fully tested it.
public static T Field<T>(this SqlDataReader sqlDataReader, string columnName)
{
int columnIndex = sqlDataReader.GetOrdinal(columnName);
if (sqlDataReader.IsDBNull(columnIndex))
{
if (default(T) != null)
{
throw new InvalidCastException("Cannot convert DBNULL value to type " + typeof(T).Name);
}
else
{
return default(T);
}
}
else
{
return sqlDataReader.GetFieldValue<T>(columnIndex);
}
}
Usage:
string fname = sqlDataReader.Field<string>("FirstName");
int? age = sqlDataReader.Field<int?>("Age");
int yearsOfExperience = sqlDataReader.Field<int?>("YearsEx") ?? 0;
Convert handles DbNull sensibly.
employee.FirstName = Convert.ToString(sqlreader.GetValue(indexFirstName));
neat one-liner:
while (dataReader.Read())
{
employee.FirstName = (!dataReader.IsDBNull(dataReader.GetOrdinal("FirstName"))) ? dataReader["FirstName"].ToString() : "";
}
you can ever check for this as well
if(null !=x && x.HasRows)
{ ....}
I am trying t get this working but somehow its going out of my hand... I want to be able to check null or empty to whatever type i assigned.
EX:
int i =0;
string mystring = "";
var reult = CheckNullOrEmpty(10) // passing int
var result 1 = CheckNullOrEmpty(mystring) // passing string
public bool CheckNullOrEmpty<T>(T value)
{
// check for null or empty for strings
// check for null i.e. 0 for int
}
can someone help me with this.. I am trying to understand how generics works for this simple method.
public static bool CheckNullOrEmpty<T>(T value)
{
if (typeof(T) == typeof(string))
return string.IsNullOrEmpty(value as string);
return value == null || value.Equals(default(T));
}
How to use:
class Stub { }
bool f1 = CheckNullOrEmpty(""); //true
bool f2 = CheckNullOrEmpty<string>(null); //true
bool f3 = CheckNullOrEmpty(0); //true
bool f4 = CheckNullOrEmpty<Stub>(null); //true
You can check against default(T);
public bool CheckNullOrEmpty<T>(T value)
{
return value == default(T);
}
For more informations: http://msdn.microsoft.com/en-us/library/xwth0h0d.aspx
You can use default() -
e.g.:
if(value != default(T))
from MSDN:
Given a variable t of a parameterized type T, the statement t = null
is only valid if T is a reference type and t = 0 will only work for
numeric value types but not for structs. The solution is to use the
default keyword, which will return null for reference types and zero
for numeric value types. For structs, it will return each member of
the struct initialized to zero or null depending on whether they are
value or reference types.
http://msdn.microsoft.com/en-us/library/xwth0h0d(v=vs.80).aspx
Because your CheckNullOrEmpty implementation differs by type, you can't have that check as a generic function.
If you use Nullable value types however, you can use GetValueOrDefault():
int? i = 0;
var result = i.GetValueOrDefault(10);
Then for string, just have an extension method:
public static string GetValueOrDefault(this string item, string defaultValue = "")
{
return !string.IsNullOrWhiteSpace(item) ? item : defaultValue;
}
Then you can do:
string i = null;
string mystring = "";
var result = i.GetValueOrDefault(mystring);
I've added a couple of re-factorings:
1. DBNull is not seen as isnullorempty so added the (value as string)
2. Passing a datatable row[column] that was created dynamically at runtime (like: row["PropertyName"]) will not see this as a string with typeof(T) due to the fact that the column type base is object. So added an extra check for typeof(object) and if not null test that the ToString() is empty value. I haven't tested this fully so may not work for all types of data columns.
public static bool CheckNullOrEmpty<T>(T value)
{
// note: this does not see DBNull as isnullorempty.
if (typeof(T) == typeof(string))
{
if (!string.IsNullOrEmpty(value as string))
{
return string.IsNullOrEmpty(value.ToString().Trim());
}
else
{
return true;
}
}
else if (typeof(T) == typeof(object))
{
// note: datatable columns are always seen as object at runtime with generic T regardless of how they are dynamically typed?
if (value != null) {
return string.IsNullOrEmpty(value.ToString().Trim());
}
}
return value == null || value.Equals(default(T));
}
I want to convert a nullable numeric into a string maintaining the null value. This is what I'm doing:
int? i = null;
string s = i == null ? null : i.ToString();
Is there something shorter?
You can write some extension method:
public static string ToNullString(this int? i)
{
return i.HasValue ? i.ToString() : null;
}
Usage will be more simple:
string s = i.ToNullString();
Or generic version:
public static string ToNullString<T>(this Nullable<T> value)
where T : struct
{
if (value == null)
return null;
return value.ToString();
}
You could create an extension method for that:
public static string ToStringOrNull<T>(this Nullable<T> nullable)
where T : struct {
return nullable.HasValue ? nullable.ToString() : null;
}
Usage:
var s = i.ToStringOrNull();
UPDATE
Since C# 6, you can use the much more convenient null-conditional operator:
var s = i?.ToString();
I think
string s = i?.ToString();
is shorter.
We can also use System.Convert i.e.
int? i = null;
string s = Convert.ToString(i); // it gives null if i is null.
And as already mentioned we can also use null conditional operator
string s = i?.ToString();
I need formatProvider parameter for decimal type so removed generic version to specialize to decimal extension as below:
public static string ToStringOrNull(this Nullable<decimal> nullable, string format = null)
{
string resTmp = "";
if (nullable.HasValue)
{
if (format != null)
{
resTmp = nullable.Value.ToString(format);
}
else
{
resTmp = nullable.ToString();
}
}
else
{
resTmp = "";
}
return resTmp;
}
I'm trying to run the following code but get a casting error.
How can I rewrite my code to achive the same ?
boolResult= (bool?)dataReader["BOOL_FLAG"] ?? true;
intResult= (int?)dataReader["INT_VALUE"] ?? 0;
Thanks
Use the "IsDbNull" method on the data reader... for example:
bool? result = dataReader.IsDbNull(dataReader["Bool_Flag"]) ? null : (bool)dataReader["Bool_Flag"]
Edit
You'd need to do something akin to:
bool? nullBoolean = null;
you'd have
bool? result = dataReader.IsDbNull(dataReader["Bool_Flag"]) ? nullBoolean : (bool)dataReader["Bool_Flag"]
Consider doing it in a function.
Here's something I used in the past (you can make this an extension method in .net 4):
public static T GetValueOrDefault<T>(SqlDataReader dataReader, System.Enum columnIndex)
{
int index = Convert.ToInt32(columnIndex);
return !dataReader.IsDBNull(index) ? (T)dataReader.GetValue(index) : default(T);
}
Edit
As an extension (not tested, but you get the idea), and using column names instead of index:
public static T GetValueOrDefault<T>(this SqlDataReader dataReader, string columnName)
{
return !dataReader.IsDBNull(dataReader[columnName]) ? (T)dataReader.GetValue(dataReader[columnName]) : default(T);
}
usage:
bool? flag = dataReader.GetValueOrDefault("BOOL_COLUMN");
There's an answer here that might be helpful:
https://stackoverflow.com/a/3308515/1255900
You can use the "as" keyword. Note the caution mentioned in the comments.
nullableBoolResult = dataReader["BOOL_FLAG"] as bool?;
Or, if you are not using nullables, as in your original post:
boolResult = (dataReader["BOOL_FLAG"] as bool?) ?? 0;
bool? boolResult = null;
int? intResult = null;
if (dataReader.IsDBNull(reader.GetOrdinal("BOOL_FLAG")) == false)
{
boolResult = dataReader.GetBoolean(reader.GetOrdinal("BOOL_FLAG"));
}
else
{
boolResult = true;
}
if (dataReader.IsDBNull(reader.GetOrdinal("INT_VALUE")) == false)
{
intResult= dataReader.GetInt32(reader.GetOrdinal("INT_VALUE"));
}
else
{
intResult = 0;
}
I'm sure I found the inspiration for this somewhere around the interweb but I can't seem to find the original source anymore. Anyway, below you find a utility class which allows to define an extension method on DataReader, like this:
public static class DataReaderExtensions
{
public static TResult Get<TResult>(this IDataReader reader, string name)
{
return reader.Get<TResult>(reader.GetOrdinal(name));
}
public static TResult Get<TResult>(this IDataReader reader, int c)
{
return ConvertTo<TResult>.From(reader[c]);
}
}
Usage:
reader.Get<bool?>("columnname")
or
reader.Get<int?>(5)
Here's the enabling utility class:
public static class ConvertTo<T>
{
// 'Factory method delegate', set in the static constructor
public static readonly Func<object, T> From;
static ConvertTo()
{
From = Create(typeof(T));
}
private static Func<object, T> Create(Type type)
{
if (!type.IsValueType) { return ConvertRefType; }
if (type.IsNullableType())
{
return (Func<object, T>)Delegate.CreateDelegate(typeof(Func<object, T>), typeof(ConvertTo<T>).GetMethod("ConvertNullableValueType", BindingFlags.NonPublic | BindingFlags.Static).MakeGenericMethod(new[] { type.GetGenericArguments()[0] }));
}
return ConvertValueType;
}
// ReSharper disable UnusedMember.Local
// (used via reflection!)
private static TElem? ConvertNullableValueType<TElem>(object value) where TElem : struct
{
if (DBNull.Value == value) { return null; }
return (TElem)value;
}
// ReSharper restore UnusedMember.Local
private static T ConvertRefType(object value)
{
if (DBNull.Value != value) { return (T)value; }
return default(T);
}
private static T ConvertValueType(object value)
{
if (DBNull.Value == value)
{
throw new NullReferenceException("Value is DbNull");
}
return (T)value;
}
}
EDIT: makes use of the IsNullableType() extension method defined like so:
public static bool IsNullableType(this Type type)
{
return
(type.IsGenericType && !type.IsGenericTypeDefinition) &&
(typeof (Nullable<>) == type.GetGenericTypeDefinition());
}
Here's my shot at an extension method. Column name semantics and falls back to default(T) when a null is encountered.
public static class DbExtensions
{
public static T ReadAs<T>(this IDataReader reader, string col)
{
object val = reader[col];
if (val is DBNull)
{
// Use the default if the column is null
return default(T);
}
return (T)val;
}
}
Here is the sample usage. Remember that despite string being a reference type, it will still fail to cast to null from a DBNull. The same is true with int?.
public Facility Bind(IDataReader reader)
{
var x = new Facility();
x.ID = reader.ReadAs<Guid>("ID");
x.Name = reader.ReadAs<string>("Name");
x.Capacity = reader.ReadAs<int?>("Capacity");
x.Description = reader.ReadAs<string>("Description");
x.Address = reader.ReadAs<string>("Address");
return x;
}
using extension method:
public static T GetValueOrDefault <T> (this SqlDataReader reader, string column) {
var isDbNull = reader[column] == DBNull.Value;
return !isDbNull ? (T) reader[column] : default (T);
}
Remember that a DBNull is not the same thing as null, so you cannot cast from one to the other. As the other poster said, you can check for DBNull using the IsDBNull() method.
Try this version. It performs some basic conversion and manages default values as well.