SQL数据读取器-处理空列值。

时间:2023-02-10 23:47:32

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.

我使用SQLdatareader从数据库构建POCOs。除非在数据库中遇到null值,否则代码是有效的。例如,如果数据库中的FirstName列包含空值,则抛出异常。

employee.FirstName = sqlreader.GetString(indexFirstName);

What is the best way to handle null values in this situation?

在这种情况下处理null值的最好方法是什么?

21 个解决方案

#1


348  

You need to check for IsDBNull:

您需要检查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.

你再也不用担心异常或空值了。

#2


191  

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.

您应该使用as操作符与??运营商为默认值。值类型需要被读取为nullable,并且给定一个默认值。

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.

作为操作符处理转换,包括检查DBNull。

#3


22  

For a string you can simply cast the object version (accessed using the array operator) and wind up with a null string for nulls:

对于一个字符串,您可以简单地转换对象版本(使用数组操作符访问)并使用null字符串结束:

employee.FirstName = (string)sqlreader[indexFirstName];

or

employee.FirstName = sqlreader[indexFirstName] as string;

For integers, if you cast to a nullable int, you can use GetValueOrDefault()

对于整数,如果将其转换为可空整数,则可以使用GetValueOrDefault()

employee.Age = (sqlreader[indexAge] as int?).GetValueOrDefault();

or the null-coalescing operator (??).

或者是零合并运算符(??)

employee.Age = (sqlreader[indexAge] as int?) ?? 0;

#4


13  

IsDbNull(int) is usually much slower than using methods like GetSqlDateTime and then comparing to DBNull.Value. Try these extension methods for SqlDataReader.

IsDbNull(int)通常比使用GetSqlDateTime等方法要慢得多,然后与DBNull.Value进行比较。为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]);

#5


10  

One way to do it is to check for db nulls:

一种方法是检查db nulls:

employee.FirstName = (sqlreader.IsDBNull(indexFirstName) 
    ? ""
    : sqlreader.GetString(indexFirstName));

#6


9  

I don't think there's a NULL column value, when rows are returned within a datareader using the column name.

我认为在使用列名称的datareader中返回行时,没有空列值。

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).

如果你datareader(“columnName”).ToString();它总是给你一个可以是空字符串(字符串)的值。如果你需要比较的话,空着。

I would use the following and wouldn't worry too much:

我会用下面的方法,不用太担心:

employee.FirstName = sqlreader["columnNameForFirstName"].ToString();

#7


8  

reader.IsDbNull(ColumnIndex) works as many answers says.

isdbnull (ColumnIndex)可以像许多答案一样工作。

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 }

#8


7  

This Solution is less vendor-dependent and works with an SQL, OleDB, and MySQL Reader:

这个解决方案不依赖于供应商,并且使用SQL、OleDB和MySQL阅读器:

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

#9


6  

What I tend to do is replace the null values in the SELECT statement with something appropriate.

我要做的是用适当的东西替换SELECT语句中的null值。

SELECT ISNULL(firstname, '') FROM people

Here I replace every null with a blank string. Your code won't throw in error in that case.

这里,我用一个空字符串替换所有null。在那种情况下,你的代码不会出错。

#10


4  

Check sqlreader.IsDBNull(indexFirstName) before you try to read it.

在尝试读取它之前,检查sqlreader.IsDBNull(indexFirstName)。

#11


2  

I think you would want to use:

我想你会想用:

SqlReader.IsDBNull(indexFirstName)

#12


2  

You can write a Generic function to check Null and include default value when it is NULL. Call this when reading Datareader

您可以编写一个泛型函数来检查Null,并在它为Null时包含默认值。在阅读Datareader时调用它。

public T CheckNull<T>(object obj)
        {
            return (obj == DBNull.Value ? default(T) : (T)obj);
        }

When reading the Datareader use

读取Datareader使用时。

                        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"]);
                         }

#13


1  

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...

我们使用一系列静态方法从数据读取器中提取所有值。因此,在本例中,我们将调用DBUtils.GetString(sqlreader(indexFirstName))创建静态/共享方法的好处是,您不必一次又一次地进行相同的检查。

The static method(s) would contain code to check for nulls (see other answers on this page).

静态方法(s)将包含用于检查nulls的代码(请参阅本页面上的其他答案)。

#14


1  

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,声明变量为。

DateTime? variable;

#15


1  

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

字符串只是返回“”,而不是0作为“”是空字符串。

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

非常灵活,因此您可以插入任何查询来读取任何列,并且它不会返回错误。

#16


0  

I am using the code listed below to handle null cells in an Excel sheet that is read in to a datatable.

我正在使用下面列出的代码来处理一个Excel表中的空单元格,它被读入一个datatable。

if (!reader.IsDBNull(2))
{
   row["Oracle"] = (string)reader[2];
}

#17


0  

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

#18


0  

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...

将缺省值(当null)替换为适合每个属性类型的值…

#19


0  

This method is dependent on indexFirstName which should be the zero-based column ordinal.

这个方法依赖于indexFirstName,它应该是从零开始的列序数。

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"];
}

#20


0  

You may use the conditional operator:

您可以使用条件操作符:

employee.FirstName = sqlreader["indexFirstName"] != DBNull.Value ? sqlreader[indexFirstName].ToString() : "";

#21


-2  

you can ever check for this as well

你也可以检查一下。

if(null !=x && x.HasRows)
{ ....}

#1


348  

You need to check for IsDBNull:

您需要检查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.

你再也不用担心异常或空值了。

#2


191  

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.

您应该使用as操作符与??运营商为默认值。值类型需要被读取为nullable,并且给定一个默认值。

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.

作为操作符处理转换,包括检查DBNull。

#3


22  

For a string you can simply cast the object version (accessed using the array operator) and wind up with a null string for nulls:

对于一个字符串,您可以简单地转换对象版本(使用数组操作符访问)并使用null字符串结束:

employee.FirstName = (string)sqlreader[indexFirstName];

or

employee.FirstName = sqlreader[indexFirstName] as string;

For integers, if you cast to a nullable int, you can use GetValueOrDefault()

对于整数,如果将其转换为可空整数,则可以使用GetValueOrDefault()

employee.Age = (sqlreader[indexAge] as int?).GetValueOrDefault();

or the null-coalescing operator (??).

或者是零合并运算符(??)

employee.Age = (sqlreader[indexAge] as int?) ?? 0;

#4


13  

IsDbNull(int) is usually much slower than using methods like GetSqlDateTime and then comparing to DBNull.Value. Try these extension methods for SqlDataReader.

IsDbNull(int)通常比使用GetSqlDateTime等方法要慢得多,然后与DBNull.Value进行比较。为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]);

#5


10  

One way to do it is to check for db nulls:

一种方法是检查db nulls:

employee.FirstName = (sqlreader.IsDBNull(indexFirstName) 
    ? ""
    : sqlreader.GetString(indexFirstName));

#6


9  

I don't think there's a NULL column value, when rows are returned within a datareader using the column name.

我认为在使用列名称的datareader中返回行时,没有空列值。

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).

如果你datareader(“columnName”).ToString();它总是给你一个可以是空字符串(字符串)的值。如果你需要比较的话,空着。

I would use the following and wouldn't worry too much:

我会用下面的方法,不用太担心:

employee.FirstName = sqlreader["columnNameForFirstName"].ToString();

#7


8  

reader.IsDbNull(ColumnIndex) works as many answers says.

isdbnull (ColumnIndex)可以像许多答案一样工作。

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 }

#8


7  

This Solution is less vendor-dependent and works with an SQL, OleDB, and MySQL Reader:

这个解决方案不依赖于供应商,并且使用SQL、OleDB和MySQL阅读器:

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

#9


6  

What I tend to do is replace the null values in the SELECT statement with something appropriate.

我要做的是用适当的东西替换SELECT语句中的null值。

SELECT ISNULL(firstname, '') FROM people

Here I replace every null with a blank string. Your code won't throw in error in that case.

这里,我用一个空字符串替换所有null。在那种情况下,你的代码不会出错。

#10


4  

Check sqlreader.IsDBNull(indexFirstName) before you try to read it.

在尝试读取它之前,检查sqlreader.IsDBNull(indexFirstName)。

#11


2  

I think you would want to use:

我想你会想用:

SqlReader.IsDBNull(indexFirstName)

#12


2  

You can write a Generic function to check Null and include default value when it is NULL. Call this when reading Datareader

您可以编写一个泛型函数来检查Null,并在它为Null时包含默认值。在阅读Datareader时调用它。

public T CheckNull<T>(object obj)
        {
            return (obj == DBNull.Value ? default(T) : (T)obj);
        }

When reading the Datareader use

读取Datareader使用时。

                        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"]);
                         }

#13


1  

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...

我们使用一系列静态方法从数据读取器中提取所有值。因此,在本例中,我们将调用DBUtils.GetString(sqlreader(indexFirstName))创建静态/共享方法的好处是,您不必一次又一次地进行相同的检查。

The static method(s) would contain code to check for nulls (see other answers on this page).

静态方法(s)将包含用于检查nulls的代码(请参阅本页面上的其他答案)。

#14


1  

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,声明变量为。

DateTime? variable;

#15


1  

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

字符串只是返回“”,而不是0作为“”是空字符串。

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

非常灵活,因此您可以插入任何查询来读取任何列,并且它不会返回错误。

#16


0  

I am using the code listed below to handle null cells in an Excel sheet that is read in to a datatable.

我正在使用下面列出的代码来处理一个Excel表中的空单元格,它被读入一个datatable。

if (!reader.IsDBNull(2))
{
   row["Oracle"] = (string)reader[2];
}

#17


0  

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

#18


0  

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...

将缺省值(当null)替换为适合每个属性类型的值…

#19


0  

This method is dependent on indexFirstName which should be the zero-based column ordinal.

这个方法依赖于indexFirstName,它应该是从零开始的列序数。

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"];
}

#20


0  

You may use the conditional operator:

您可以使用条件操作符:

employee.FirstName = sqlreader["indexFirstName"] != DBNull.Value ? sqlreader[indexFirstName].ToString() : "";

#21


-2  

you can ever check for this as well

你也可以检查一下。

if(null !=x && x.HasRows)
{ ....}