SQL Data Reader - 处理空列值

366

我正在使用 SQLdatareader 从数据库中构建 POCOs。代码运行良好,除非在数据库中遇到空值。例如,如果数据库中的 FirstName 列包含空值,将抛出异常。

employee.FirstName = sqlreader.GetString(indexFirstName);

如何在这种情况下处理空值?

2
我认为@Vijai创建的通用函数应该在这个线程中得到更多的认可。它对我来说非常有效,我不需要每次传递数据读取器对象。许多流行的答案都传递了数据读取器对象,这是不必要且沉重的。 - MSBI-Geek
30个回答

2

这是一个帮助类,如果其他人需要,可以基于@marc_s的答案使用:

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

2
我尽力重新实现了来自DataTableField方法。 https://learn.microsoft.com/en-us/dotnet/api/system.data.datarowextensions.field 如果您尝试将DBNull.Value转换为非可空类型,它将抛出异常。否则,它将DBNull.Value转换为null
我还没有完全测试过它。
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);
    }
}

使用方法:

string fname = sqlDataReader.Field<string>("FirstName");
int? age = sqlDataReader.Field<int?>("Age");
int yearsOfExperience = sqlDataReader.Field<int?>("YearsEx") ?? 0;

1
此方法依赖于 indexFirstName,该值应为基于零的列序号。
if(!sqlReader.IsDBNull(indexFirstName))
{
  employee.FirstName = sqlreader.GetString(indexFirstName);
}

如果您不知道列索引但想要检查名称,可以使用此扩展方法:

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

使用类似以下的方法:
if(sqlReader.HasColumn("FirstName"))
{
  employee.FirstName = sqlreader["FirstName"];
}

1

旧问题,但可能仍有人需要答案

实际上,我是这样解决这个问题的

对于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;
    }

对于字符串,返回空字符串 "" 而不是0。因为空字符串表示为空。所以你可以像这样使用它:
int TotalPoints = GatDataInt(QueryToGetTotalPoints, TotalPointColumn) as int?;

并且

string Email = GatDatastring(QueryToGetEmail, EmailColumn) as string;

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

1

可以使用三元运算符进行赋值:

employee.FirstName = rdr.IsDBNull(indexFirstName))? 
                     String.Empty: rdr.GetString(indexFirstName);

根据每个属性类型适当地替换默认值(当为null时)...


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

1
我正在使用下面列出的代码来处理在读入数据表时Excel表格中的空单元格。
if (!reader.IsDBNull(2))
{
   row["Oracle"] = (string)reader[2];
}

1

简洁的一行代码:

    while (dataReader.Read())
{
    employee.FirstName = (!dataReader.IsDBNull(dataReader.GetOrdinal("FirstName"))) ? dataReader["FirstName"].ToString() : "";
}

0

合理地处理 DbNull 的句柄。

employee.FirstName = Convert.ToString(sqlreader.GetValue(indexFirstName));

请注意,DBNull 被转换为空字符串,而不是空值。 - Rhys Jones

-3
你也可以检查这个
if(null !=x && x.HasRows)
{ ....}

-1 这不是重点:我们正在处理空列值的情况,而不是空的或空的 SqlDataReader 的情况。 - bluish

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接