Reputation:
I have the following table:
CREATE TABLE [dbo].[CATEGORIE](
[bijdrage_id] [int] NOT NULL,
[categorie_id] [int] NULL,
[naam] [nvarchar](255) NOT NULL,)
I use this query to retrieve the data:
select c.bijdrage_id, c.categorie_id AS Subcategorievan, c.Naam from CATEGORIE as c
With the following c# code I put all my values into Categorie objects:
public List<Categorie> geefAlleCategorien()
{
List<Categorie> categorien = new List<Categorie>();
string query = "select c.bijdrage_id, c.categorie_id as SubCategorieVan, c.Naam from CATEGORIE as c";
SqlDataReader reader = db.Select(query);
while (reader.Read())
{
Categorie c = new Categorie();
c.Id = reader.GetInt32(0);
c.SubCategorieVan = reader.GetString(1);
c.Naam = reader.GetString(2);
categorien.Add(c);
}
db.Close();
return categorien;
}
My problem is that some of the values in the "categorie_id" column are NULL and the "reader.GetString(1)" method can't handle NULL values.
How can handle these NULL values with my c# code?
Upvotes: 0
Views: 282
Reputation: 12934
The problem is, a null
in the database does not return a C# null
, but a DbNull.Value
. If a c# null
was returned, the problem would be solved for all reference types (but not all value type). So when a column inside a database is nullable, you have to check for a DbNull.Value
.
You have serveral options:
SqlDataReader.IsDbNull(...)
. as
operator in combination with SqlDataReader.GetValue(...)
. This works only with nullable types.Examples:
c.SubCategorieVan = reader.IsDbNull(1) ? null : reader.GetString(1);
or
c.SubCategorieVan = reader.GetValue(1) as string;
Or... if you want to give your properties a default value, when a DbNull is returned, you can give a default value in your code:
c.SubCategorieVan = reader.IsDbNull(1) ? "Leeg" : reader.GetString(1);
or
c.SubCategorieVan = reader.GetValue(1) as string ?? "Leeg";
You could create an extension method:
static public T GetValue<T>(this IDataReader reader, int columnIndex, T defaultValue = default(T))
{
return reader.IsDbNull(columnIndex) ? defaultValue : (T)reader.GetValue(columnIndex)
}
This way, your reading method could become nice and clean:
c.Id = reader.GetValue<int>(0);
c.SubCategorieVan = reader.GetValue<string>(1, "Leeg"); // In case you want to use this default value.
c.Naam = reader.GetValue<string>(2);
Upvotes: 1
Reputation: 82534
Everything is better with extension methods....
Here is a little gem I've found a long time ago somewhere on the internet:
public static class IDataReaderExtensions
{
public static T GetValueOrDefault<T>(this IDataReader reader, int index)
{
return (Convert.IsDBNull(reader[index])) ? default(T) : (T)reader.GetValue(index);
}
public static T GetValueOrDefault<T>(this IDataReader reader, string name)
{
return reader.GetValueOrDefault<T>(reader.GetOrdinal(name));
}
}
And then you use it like this:
c.SubCategorieVan = reader.GetValueOrDefault<int>(1);
Upvotes: 0
Reputation: 77936
Well you can use COALESCE()
function in your SQL and return a default value like
select c.bijdrage_id,
coalesce(c.categorie_id,0) AS Subcategorievan,
c.Naam
from CATEGORIE as c
Upvotes: 2
Reputation: 460340
You can use IsDBNull
:
Categorie c = new Categorie();
c.Id = reader.GetInt32(0);
c.SubCategorieVan = reader.IsDBNull(1) ? null : reader.GetString(1);
c.Naam = reader.GetString(2);
categorien.Add(c);
Upvotes: 3