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

employee.FirstName = sqlreader.GetString(indexFirstName);

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


当前回答

当在数据读取器中使用列名返回行时,我不认为有NULL列值。

如果你做datareader["columnName"].ToString();它总是会给你一个值,可以是一个空字符串(字符串。如果需要比较,则为空)。

我会使用以下方法,不会太担心:

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

其他回答

整洁的小笑话:

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

如何创建帮助方法

为字符串

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

        return o.ToString();
    }

使用

MyStringConverter(read["indexStringValue"])

为整数

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

DateTime? variable;

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

这里有很多有用的信息(和一些错误的信息)的答案,我想把它们放在一起。

这个问题的简短回答是检查DBNull -几乎每个人都同意这一点:)

与使用辅助方法读取每个SQL数据类型的可空值不同,泛型方法允许我们用更少的代码来解决这个问题。然而,对于可空值类型和引用类型,你不能有一个单一的泛型方法,这将在中详细讨论 可空类型作为泛型参数可能吗?和c#泛型类型约束为所有可空的。

所以,从@ZXX和@getpsyched的答案中,我们最终得到了这个,2个方法用于获取可空值,我已经添加了第三个非空值(它完成了基于方法命名的集合)。

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

我通常使用列名,如果你使用列索引,可以修改这些。根据这些方法名,我可以判断我是否期望数据为空,这在查看很久以前编写的代码时非常有用。

提示;

数据库中没有可空列可以避免这个问题。如果你 对数据库有控制那么列应该非空由 默认值,只在必要时为空。 不要强制转换数据库值 使用c#的“as”操作符,因为如果强制转换错误,它就会 静默返回null。 使用默认值表达式将会改变 数据库空值到非空值的值类型,如int, datetime, 钻头等。

最后,在测试所有SQL Server数据类型的上述方法时,我发现你不能直接从SqlDataReader中获得一个char[],如果你想要一个char[],你必须获得一个字符串并使用ToCharArray()。

老问题了,但也许有人还需要一个答案

在现实生活中,我就是这样解决这个问题的

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

and

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

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