2008-08-25 105 views
41

我经常遇到问题处理DataRowsSqlDataAdapters返回。当我尝试填补对象使用这样的代码:什么是最好的方式来处理DBNull的

DataRow row = ds.Tables[0].Rows[0]; 
string value = (string)row; 

什么是这种类型的情况来处理DBNull's的最佳途径。

+0

密切:[最高效的单向到检查换的DBNull和 - 然后,分配到一个变量(http://stackoverflow.com/questions/221582/most-efficient-way -to-检查换为DBNull和-然后指派到一个变量) – nawfal 2013-12-11 16:42:38

回答

34

可以为空的类型是好的,但只适用于不能以空格开头的类型。

为了一种“可空”问号追加到类型,例如:

int? value = 5; 

我也建议使用“as”关键字,而不是铸造的。您只能在可为空的类型上使用“as”关键字,因此请确保您正在投射已经为空的东西(如字符串),或者使用上面提到的可空类型。这样做的原因是

  1. 如果一个类型是空的,则“as”关键字返回null如果值是DBNull
  2. 它是ever-so-slightly faster than casting虽然only in certain cases。这本身并不是一个足够好的理由来使用as,但加上它的原因是有用的。

我建议你做这样的事情

DataRow row = ds.Tables[0].Rows[0]; 
string value = row as string; 

在上述情况下,如果row回来为DBNull,然后value将成为null,而不是抛出异常。请注意,如果您的数据库查询更改了返回的列/类型,使用as将导致您的代码在默认情况下失败并使值简单null而不是在返回不正确的数据时抛出相应的异常,因此建议您进行测试以其他方式验证您的查询,以确保您的代码库发展时的数据完整性。

6

添加对System.Data.DataSetExtensions的引用,该引用添加了Linq对查询数据表的支持。

这将是这样的:

string value = (
    from row in ds.Tables[0].Rows 
    select row.Field<string>(0)).FirstOrDefault(); 
+2

+1:这个答案应该是更upvoted大概也接受了 - 绝对row.Field (“栏”)是最有效的,用于处理null(DBNull.Value)的可读和干净的解决方案。还有用于将值写入行的row.SetField (“column_name”,value)。 – 2012-12-19 23:20:45

2

我平时写一个封装内置Convert类我自己ConvertDBNull类。如果该值为DBNull,则它将返回null(如果其引用类型)或默认值(如果其值类型)。 例子: - ConvertDBNull.ToInt64(object obj)回报Convert.ToInt64(obj)除非obj是为DBNull在这种情况下,如果你不使用可空类型,它将返回0。

21

,做的最好的事情就是检查是否该列的值是为DBNull。如果它是DBNull,那么设置你对相应的数据类型使用null/empty的引用。

DataRow row = ds.Tables[0].Rows[0]; 
string value; 

if (row["fooColumn"] == DBNull.Value) 
{ 
    value = string.Empty; 
} 
else 
{ 
    value = Convert.ToString(row["fooColumn"]); 
} 

随着马努说,你可以创建每个类型的重载转换方法的转换类,所以你不if/else语句块必须辣椒代码。

但是我会强调,如果你可以使用它们,可以为空的类型是更好的路径。理由是,对于非空类型,您将不得不求助于“幻数”来表示空值。例如,如果你将一个列映射到一个int变量,你将如何表示DBNull?通常你不能使用0,因为在大多数程序中0有一个有效的含义。通常我会看到人们将DBNull映射到int.MinValue,但这可能也有问题。我最好的建议是这样的:

  • 对于在数据库中可以为空的列,请使用可为空的类型。
  • 对于数据库中不能为空的列,请使用常规类型。

可以使用可为空的类型来解决这个问题。话虽如此,如果您使用的是旧版本的框架,或者为不支持可空类型的人员工作,那么代码示例就可以解决这个问题。

+0

行if(行[“fooColumn”] == DBNull.Value)的作品,但不正确。它没有被定义DBNull.Value应该被实现为Singleton模式。更好的一行是:if(row [“fooColumn”]是DBNull) – doekman 2009-06-12 08:30:32

+0

@doekman - 实际上,DBNull *是一个单例类。引用MSDN:“DBNull是一个单例类,这意味着只有这个类的[DBNull.Value]实例可以存在。” http://msdn.microsoft.com/en-us/library/system.dbnull.value.aspx – Greg 2009-12-22 16:39:42

+2

如果你想治疗的DBNull为空字符串行[“fooColumn”]。的ToString()将做到这一点。 – samir105 2012-12-23 08:27:46

1

出于某种原因,我已经受够了做对DBNull.Value检查的问题,所以我已经做过的事情有所差异,DataRow对象中的杠杆属性:

if (row.IsNull["fooColumn"]) 
{ 
    value = string.Empty(); 
} 
{ 
else 
{ 
    value = row["fooColumn"].ToString; 
} 
5

如果你有控制即返回结果的查询,你可以使用ISNULL()返回非空值是这样的:

SELECT 
    ISNULL(name,'') AS name 
    ,ISNULL(age, 0) AS age 
FROM 
    names 

如果你的情况可以容忍这些魔法值代替NULL,采用这种方法可以解决这个问题通过你的整个应用程序,而不会混淆你的码。

8

我总是发现使用If/Else检查版本的清晰,简洁和无问题,只能使用三元运算符。将所有内容保留在一行上,包括如果列为空,则分配默认值。

因此,假设名为“MyCol”一空Int32列,在这里我们想返回-99如果列空,但返回整数值如果列不为空:

return row["MyCol"] == DBNull.Value ? -99 : Convert.ToInt32(Row["MyCol"]); 

这是与上面的If/Else获胜者相同的方法 - 但是我发现,如果您从数据读取器中读取多列,这是一个真正的奖励,所有列读线都排在一起,排列整齐,因为它更容易现场错误:

Object.ID = DataReader["ID"] == DBNull.Value ? -99 : Convert.ToInt32(DataReader["ID"]); 
Object.Name = DataReader["Name"] == DBNull.Value ? "None" : Convert.ToString(DataReader["Name"]); 
Object.Price = DataReader["Price"] == DBNull.Value ? 0.0 : Convert.ToFloat(DataReader["Price"]); 
0

如果您担心在预期时获取DBNull g字符串,一种选择是将DataTable中的所有DBNull值转换为空字符串。

这样做很简单,但会增加一些开销,特别是在处理大型数据表时。选中此link,显示如何做到这一点,如果你有兴趣

+0

Someties知道空字符串和空字符串之间的区别很重要。例如,将值设置为空字符串,而不是仅设置值。 – Mykroft 2008-10-24 17:44:12

1

布拉德·艾布拉姆斯发布有关短短几天前 http://blogs.msdn.com/brada/archive/2009/02/09/framework-design-guidelines-system-dbnull.aspx

总结的东西“避免使用System.DBNull。身高可空来代替。“

这里是我的两分钱(未经测试的代码:))

// Or if (row["fooColumn"] == DBNull.Value) 
if (row.IsNull["fooColumn"]) 
{ 
    // use a null for strings and a Nullable for value types 
    // if it is a value type and null is invalid throw a 
    // InvalidOperationException here with some descriptive text. 
    // or dont check for null at all and let the cast exception below bubble 
    value = null; 
} 
else 
{ 
    // do a direct cast here. dont use "as", "convert", "parse" or "tostring" 
    // as all of these will swallow the case where is the incorect type. 
    // (Unless it is a string in the DB and really do want to convert it) 
    value = (string)row["fooColumn"]; 
} 

而且一个问题......你没有使用ORM的原因吗?

3

的DBNull实现的ToString() 。像其他一切不需要做任何事情而不是硬投,调用该对象的的ToString()方法

DataRow row = ds.Tables[0].Rows[0]; 
string value; 

if (row["fooColumn"] == DBNull.Value) 
{ 
    value = string.Empty; 
} 
else 
{ 
    value = Convert.ToString(row["fooColumn"]); 
} 

这将成为:

DataRow row = ds.Tables[0].Rows[0]; 
string value = row.ToString() 

DBNull.ToString()返回的String.Empty

我会想象这是你要找的

1

最好的做法你也应该看看扩展方法。 Here是处理这个scenerio的一些例子。

推荐read

3

值得一提的是,这DBNull.Value.ToString()等于String.Empty

你可以用你的优势:

DataRow row = ds.Tables[0].Rows[0]; 
string value = row["name"].ToString(); 

然而,这仅适用于弦乐,其他一切我会使用linq方式或扩展方法。至于我自己,我写了检查的DBNull一点点扩展方法,并与数据表工作时,即使不通过Convert.ChangeType(...)

int value = row.GetValueOrDefault<int>("count"); 
int value = row.GetValueOrDefault<int>("count", 15); 
2

通常情况下,铸造你必须处理这种情况下,如果行字段可以是零或DBNull的,通常我处理,像这样:

string myValue = (myDataTable.Rows[i]["MyDbNullableField"] as string) ?? string.Empty; 

的“为”经营者返回null无效转换的,像DBNull的字符串,而“?”如果第一个为空,则返回 表达式右侧的项。

相关问题