如何从数据库datareader解析值并处理可能的NULL值?

时间:2011-02-16 14:43:13

标签: c# vb.net null types

我已经遇到过这个问题几次,从来没有得到一个好的答案。我认为其他人必须已经处理过这个问题。

我有一个从数据库返回的datareader,我想使用其中的值,但值可能包含也可能不包含NULL。我想有一个辅助函数,它接受来自datareader的值,如果它不是NULL则返回值,如果它是NULL,则返回空格。

我遇到的问题是我正在测试的变量的数据类型是可变的。它可以是String,Integer或DateTime。任何人都可以建议一种简单的方法来测试该值,然后返回原始值(如果可能的话,返回相同的数据类型)或其他什么,如果它是NULL?

我目前正在使用VB.NET,但我也想知道如何在C#中执行此操作。谢谢。

5 个答案:

答案 0 :(得分:8)

这应该适用于我认为的大多数事情(我没有经过考验):

 public T ParseValue<T>(System.Data.SqlClient.SqlDataReader reader, string column)
 {
     T result = default(T);

     if (!reader.IsDBNull(reader.GetOrdinal(column)))
         result = (T)reader.GetValue(reader.GetOrdinal(column));

     return result;
 }

如果是null

,则会返回该类型的默认值

答案 1 :(得分:2)

int v = dr.GetValue<int>("vvv");             // throws if column is null
int? w = dr.GetValue<int?>("www");           // set to null if column is null
int x = dr.GetValue<int?>("xxx") ?? -1;      // set to -1 if column is null
string y = dr.GetValue<string>("yyy");       // set to null if column is null
string z = dr.GetValue<string>("zzz") ?? ""  // set to "" if column is null

// ...

public static T GetValue<T>(this IDataRecord source, string fieldName)
{
    return source.GetValue<T>(source.GetOrdinal(fieldName));
}

public static T GetValue<T>(this IDataRecord source, int fieldIndex)
{
    if (source == null)
        throw new ArgumentNullException("source");

    if (fieldIndex < 0)
        throw new ArgumentOutOfRangeException("fieldIndex", fieldIndex,
                                              "Index cannot be negative.");

    if (source.IsDBNull(fieldIndex))
    {
        T defaultValue = default(T);
        if (defaultValue == null)
            return defaultValue;
    }

    // throws if the field is null and T is a non-nullable value type
    return (T)source.GetValue(fieldIndex);
}

答案 2 :(得分:2)

我使用一个扩展方法,它接受一个对象,期望/最终类型和默认值。如果对象为null(或DBNull),则返回默认值。如果对象可以转换为最终/期望类型,则执行转换并返回强类型对象。如果转换失败,则返回默认值或根据您是否严格而引发异常。这是方法的样子 -

    /// <summary>
    /// Gets the non null value.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="item">The item.</param>
    /// <param name="defaultValue">The default value.</param>
    /// <param name="strict">if set to <c>true</c> [strict].</param>
    /// <returns></returns>
    [DebuggerStepThrough]
    public static T GetNonNullValue<T>(this object item, T defaultValue, bool strict) {
        if(item.IsNullOrEmpty() || item == DBNull.Value) {
            return defaultValue;
        }

        var originalType = item.GetType();
        var targetType = typeof(T);

        if(originalType == targetType || originalType.IsSubclassOf(targetType)) {
            return (T)item;
        }

        TypeConverter typeConverter = TypeDescriptor.GetConverter(targetType);
        if(typeConverter.CanConvertFrom(originalType)) {
            return (T)typeConverter.ConvertFrom(item);
        }

        typeConverter = TypeDescriptor.GetConverter(originalType);
        if(typeConverter.CanConvertTo(targetType)) {
            return (T)typeConverter.ConvertTo(item, targetType);
        }

        if(strict) {
            throw new QIGException("Conversion from {0} to {1} failed!", originalType, targetType);
        }

        return defaultValue;
    }

EDIT1: 为了澄清,您将在数据阅读器中使用此功能 -

        SqlDataReader dr = GetResultsIntoDataReader();
        string column1Value = dr["ColumnName1"].GetNonNullValue(String.Empty);
        int? column2Value = dr["ColumnName2"].GetNonNullValue(new Nullable<int>());
        double column3Value = dr["ColumnName3"].GetNonNullValue(0.0);

答案 3 :(得分:2)

我发现w69rdy的答案对SQL Money类型或数字不起作用。我尝试使用它将Money转换为float和double。都没有奏效。我将我的Money类型转换为Numeric(18,4),但它仍然不会转换为float或double。

在所有情况下,它都会抛出一个类型转换异常。

然而,我确实得到了YetAnotherUser的答案,只需要做一些小改动。

不得不改变:

if(item.IsNullOrEmpty() || item == DBNull.Value)

if(item == null || item == DBNull.Value) **

抛出新的QIGException(“从{0}转换为{1}失败!”,originalType,targetType);

throw new Exception(string.Format("Conversion from {0} to {1} failed!", originalType, targetType));

还补充说:

public static T GetNonNullValue<T>(this object item, T defaultValue)
{
    return item.GetNonNullValue(defaultValue, true);
}

所以电话可能是:

curInsurance.Pharmacy = dataReader["Pharmacy"].GetNonNullValue(-1d);

不是

curInsurance.Pharmacy = dataReader["Pharmacy"].GetNonNullValue(-1d, true);

此外,我不得不阅读有关自定义扩展的内容,但是男人很酷。我将不得不再探索一下。

答案 4 :(得分:0)

您可以使用IDataReader.IsDBNull方法检查数据库中的字段是否为NULL。