首页 文章

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

提问于
浏览
248

我正在使用SQLdatareader从数据库构建POCO . 代码工作,除非它在数据库中遇到空值 . 例如,如果数据库中的FirstName列包含空值,则抛出异常 .

employee.FirstName = sqlreader.GetString(indexFirstName);

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

22 回答

  • 1

    您可以编写一个Generic函数来检查Null,并在它为NULL时包含默认值 . 读取Datareader时调用此方法

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

    在阅读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"]);
                             }
    
  • 7

    您应该将 as 运算符与 ?? 运算符结合使用以获取默认值 . 值类型需要被读取为可空并给定默认值 .

    employee.FirstName = sqlreader[indexFirstName] as string;
    employee.Age = sqlreader[indexAge] as int? ?? default(int);
    

    as 运算符处理转换,包括检查DBNull .

  • -2

    我想你会想要使用:

    SqlReader.IsDBNull(indexFirstName)
    
  • 11

    我使用下面列出的代码来处理读入数据表的Excel工作表中的空单元格 .

    if (!reader.IsDBNull(2))
    {
       row["Oracle"] = (string)reader[2];
    }
    
  • 26
    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();
            }
    
  • 6

    你也可以检查这个

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

    当使用列名称在datareader中返回行时,我不会 NULLNULL 列值 .

    如果你执行 datareader["columnName"].ToString(); 它将始终为您提供一个可以为空字符串的值(如果需要比较,则为 String.Empty ) .

    我会使用以下内容,不会太担心:

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

    一种方法是检查db nulls:

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

    你需要检查 IsDBNull

    if(!SqlReader.IsDBNull(indexFirstName))
    {
      employee.FirstName = sqlreader.GetString(indexFirstName);
    }
    

    这是您检测和处理这种情况的唯一可靠方法 .

    我将这些内容包装到扩展方法中,如果列确实是 null ,则往往会返回默认值:

    public static string SafeGetString(this SqlDataReader reader, int colIndex)
    {
       if(!reader.IsDBNull(colIndex))
           return reader.GetString(colIndex);
       return string.Empty;
    }
    

    现在你可以像这样调用它:

    employee.FirstName = SqlReader.SafeGetString(indexFirstName);
    

    而且你永远不必再担心异常或 null 值 .

  • 1

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

    像这样使用它们:

    var dd = r.Val<DateTime>(ords[4]);
    var ii = r.Def<int>(ords[0]);
    int nn = r.Def<int>(ords[0]);
    
  • 9

    此解决方案不依赖于供应商,可与SQL,OleDB和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);
    }
    
  • 1

    在尝试阅读之前检查 sqlreader.IsDBNull(indexFirstName) .

  • 383

    和/或使用三元运算符和赋值:

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

    替换每个属性类型的默认值(当为null时)...

  • 18

    如何创建帮助方法

    对于String

    private static string MyStringConverter(object o)
        {
            if (o == DBNull.Value || o == null)
                return "";
    
            return o.ToString();
        }
    

    用法

    MyStringConverter(read["indexStringValue"])
    

    对于Int

    private static int MyIntonverter(object o)
        {
            if (o == DBNull.Value || o == null)
                return 0;
    
            return Convert.ToInt32(o);
        }
    

    用法

    MyIntonverter(read["indexIntValue"])
    

    对于日期

    private static DateTime? MyDateConverter(object o)
        {
            return (o == DBNull.Value || o == null) ? (DateTime?)null : Convert.ToDateTime(o);
        }
    

    用法

    MyDateConverter(read["indexDateValue"])
    

    注意:对于DateTime,将varialbe声明为

    DateTime? variable;
    
  • 0

    您可以使用条件运算符:

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

    我们使用一系列静态方法从数据读取器中提取所有值 . 所以在这种情况下我们会调用 DBUtils.GetString(sqlreader(indexFirstName)) 创建静态/共享方法的好处是你不必一遍又一遍地做同样的检查......

    静态方法将包含检查空值的代码(请参阅本页的其他答案) .

  • 9

    老问题,但也许有人仍然需要一个答案

    实际上,我解决了这个问题

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

    非常灵活,所以你可以插入任何查询来读取任何列,它永远不会返回错误

  • 10

    我倾向于用适当的东西替换SELECT语句中的空值 .

    SELECT ISNULL(firstname, '') FROM people
    

    在这里,我用空字符串替换每个null . 在这种情况下,您的代码不会出错 .

  • 2

    作为marc_s的答案的补充,您可以使用更通用的扩展方法从SqlDataReader获取值:

    public static T SafeGet<T>(this SqlDataReader reader, int col)
        {
            return reader.IsDBNull(col) ? default(T) : reader.GetFieldValue<T>(col);
        }
    
  • 3

    对于字符串,您可以简单地转换对象版本(使用数组运算符访问)并使用null字符串为null:

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

    要么

    employee.FirstName = sqlreader[indexFirstName] as string;
    

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

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

    或null-coalescing运算符( ?? ) .

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

    reader.IsDbNull(ColumnIndex) 正如许多答案所说 .

    我想提一下,如果你使用列名,只比较类型可能会更舒服 .

    if(reader["TeacherImage"].GetType() == typeof(DBNull)) { //logic }
    
  • 207

    此方法依赖于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"];
    }
    

相关问题