如何使用 SqlDataRecord 处理 Nullable 类型
Posted
技术标签:
【中文标题】如何使用 SqlDataRecord 处理 Nullable 类型【英文标题】:How do you handle Nullable type with SqlDataRecord 【发布时间】:2012-01-14 08:59:00 【问题描述】:我正在解析 XML (LINQ to XML),并且在元素/属性为空的情况下使用可空类型(int?
和 decimal?
)。但是,在构建我的集合以传递给数据库(使用 TVP)时,我不知道如何处理值实际上为空的情况。我不能将 null 传递给 SqlDataRecord SetInt32 或 SetDecimal,我不想设置为零....我实际上希望它为 null。
告诉我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);
任何想法如何在不传递零(保持空值)的情况下处理这个问题?
【问题讨论】:
【参考方案1】:正如@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);
【讨论】:
【参考方案2】:也许你可以试试下面的。
if(dm.Count == null)
rec.SetDBNull(2)
else
rec.SetString(2, dm.Count);
【讨论】:
【参考方案3】:扩展方法:
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()
需要的指令更少,并且更有可能被内联,因此它更适合编译器和处理器。
【讨论】:
SetValue(ordinal,object) 处理可空值和空值,但在类型和值长度检查方面有一点开销。性能差异可能不明显。 @RichardCollette 感谢您的评论;我没有想到。我怀疑您是对的,对于大多数应用程序而言,性能差异可能微不足道。不过,我确实倾向于基于哲学理由更喜欢更强的打字。您的评论也启发了我添加一个两年前我没有想到的小优化。 不确定框架是否发生了变化,但它在版本 4 中是 SetDBNull(注意“B”大小写)。 @PhilCooper 什么 版本 4 中的 SetDBNull 是什么?什么“B”案例? @phoog SetDbNull 是 SetDBNull 参见此处:SqlDataRecord.SetDBNull【参考方案4】://我发现这在检查或处理可空类型时最适合我 //在我的示例中,我正在检查存储在 String[] 数组中的值
sqlcmdUpdateRecord.Parameters.AddWithValue("@strSomeValue", (strRecord[(int)
DataFields.SomeDataField] as object) ?? DBNull.Value);
【讨论】:
【参考方案5】:应该使用SetSqlInt32
而不是SetString
。试试
rec.SetSqlInt32(2, (dm.Count.HasValue ? new SqlInt32(dm.Count) : SqlInt32.Null) );
【讨论】:
那必须是rec.SetSqlInt32(2, (dm.Count.HasValue ? new SqlInt32(dm.Count.Value) : SqlInt32.Null) );
此外,正如我在编辑答案时意识到的那样,从 int 到 SqlInt32 的隐式转换意味着您可以这样做:rec.SetSqlInt32(2, dm.Count.HasValue ? dm.Count.Value : SqlInt32.Null);
【参考方案6】:
我从未使用过SqlDataRecord
,但在使用DataTable
和DataRow
时,或者在使用参数化查询时,我使用DBNull.Value
指定null
。
使用SqlDataRecord
,看起来您可以使用SetDBNull
方法。
【讨论】:
以上是关于如何使用 SqlDataRecord 处理 Nullable 类型的主要内容,如果未能解决你的问题,请参考以下文章
如何从PowerShell /批处理文件中的网络路径运行命令