如何使用SqlDataRecord处理Nullable类型?

本文关键字:类型 Nullable 处理 何使用 SqlDataRecord | 更新日期: 2023-09-27 18:17:11

我正在解析XML (LINQ到XML),并且在元素/属性为空的情况下使用可空类型(int?decimal?)。然而,当构建我的集合传递给数据库(使用TVP),我不知道如何处理的情况下,值实际上是空的。我不能传递一个空到SqlDataRecord settint32或SetDecimal,我不想设置为零....我想让它为空

告诉我int没有过载?

Count是一个可空的类型(int? Count)

SqlDataRecord rec = new SqlDataRecord(
              new SqlMetaData("Name", SqlDbType.VarChar, 50),
              new SqlMetaData("Type", SqlDbType.VarChar, 50),
              new SqlMetaData("Count", SqlDbType.Int));
   rec.SetString(0, dm.Name);
   rec.SetString(1, dm.Type);
   rec.SetString(2, dm.Count);

任何想法如何处理这个没有传递零(维护null)?

如何使用SqlDataRecord处理Nullable类型?

扩展方法:

static class SqlDataRecordExtensions
{
    static void SetNullableInt32(this SqlDataRecord rec, int index, Int32? value)
    {
        if (value.HasValue)
            rec.SetInt32(index, value.GetValueOrDefault());
        else
            rec.SetDBNull(index);
    }
}

或者,按照D Stanley的建议使用SetSqlInt32:

static class SqlDataRecordExtensions
{
    static void SetNullableInt32(this SqlDataRecord rec, int index, Int32? value)
    {
        rec.SetSqlInt32(index, value.HasValue ? value.GetValueOrDefault() : SqlInt32.Null);
        //                                      ^^^^^^^^^^^^^^^^^^^^^^^^^
        //                                      You can leave out the cast to (SqlInt32),
        //                                      because the conversion is implicit
    }
}

注意,2013年12月9日:由于评论,我回到这个答案,我注意到一个小小的改进机会,基于Eric Lippert关于可空微优化的系列,可以在http://ericlippert.com/2012/12/20/nullable-micro-optimizations-part-one/找到。

简而言之,虽然Value属性需要更少的输入,因此对程序员来说可以说是更理想的,但如果HasValue为false,它必须抛出异常。另一方面,GetValueOrDefault()方法是一个简单的字段访问。正因为如此,GetValueOrDefault()需要更少的指令,更有可能是内联的,所以它对编译器和处理器来说更理想。

我从来没有使用过SqlDataRecord,但是当使用DataTableDataRow时,或者使用参数化查询时,我使用DBNull.Value指定null

对于SqlDataRecord,看起来您可以使用SetDBNull方法

按照@phoog的建议,不同类型的扩展方法:

public static class ExtensionSqlDataRecord
{
    public static void SetDateTime(this SqlDataRecord record, int ordinal, DateTime? value)
    {
        if (value != null)
        {
            record.SetDateTime(ordinal, (DateTime)value);
        }
        else
        {
            record.SetDBNull(ordinal);
        }
    }
    public static void SetInt32(this SqlDataRecord record, int ordinal, int? value)
    {
        if (value != null)
        {
            record.SetInt32(ordinal, (int)value);
        }
        else
        {
            record.SetDBNull(ordinal);
        }
    }
    public static void SetByte(this SqlDataRecord record, int ordinal, byte? value)
    {
        if (value != null)
        {
            record.SetByte(ordinal, (byte)value);
        }
        else
        {
            record.SetDBNull(ordinal);
        }
    }
    public static void SetDecimal(this SqlDataRecord record, int ordinal, decimal? value)
    {
        if (value != null)
        {
            record.SetDecimal(ordinal, (decimal)value);
        }
        else
        {
            record.SetDBNull(ordinal);
        }
    }
    public static void SetBoolean(this SqlDataRecord record, int ordinal, bool? value)
    {
        if (value != null)
        {
            record.SetBoolean(ordinal, (bool)value);
        }
        else
        {
            record.SetDBNull(ordinal);
        }
    }
}

应该使用SetSqlInt32而不是SetString。试着

rec.SetSqlInt32(2, (dm.Count.HasValue ? new SqlInt32(dm.Count) : SqlInt32.Null) );

//我发现在检查或处理可空类型时,这对我来说是最好的//在我的例子中,我正在检查存储在String[]数组中的值

sqlcmdUpdateRecord.Parameters.AddWithValue("@strSomeValue", (strRecord[(int) 
DataFields.SomeDataField] as object) ?? DBNull.Value);

也许你可以试试下面的方法。

if(dm.Count == null){
  rec.SetDBNull(2)
}
else{
 rec.SetString(2, dm.Count);
}