我在处理DataRows
返回的SqlDataAdapters
时经常遇到问题。当我尝试使用如下代码填充对象时:
DataRow row = ds.Tables[0].Rows[0];
string value = (string)row;
在这种情况下处理DBNull's
的最佳方法是什么。
答案 0 :(得分:36)
可以为空的类型很好,但仅适用于不能开头的类型。
要使类型为“可空”,请在类型中附加问号,例如:
int? value = 5;
我还建议使用“as
”关键字而不是强制转换。您只能在可空类型上使用“as”关键字,因此请确保您正在构建已经可以为空的内容(如字符串),或者使用如上所述的可空类型。原因是
as
”关键字返回null
,如果值为DBNull
。as
,但加上上面的原因它很有用。我建议做这样的事情
DataRow row = ds.Tables[0].Rows[0];
string value = row as string;
在上述情况下,如果row
返回DBNull
,则value
将变为null
,而不是抛出异常。请注意,如果您的数据库查询更改了要返回的列/类型,使用as
将导致您的代码无声地失败并使值变为简单null
而不是抛出相应的异常如果返回了不正确的数据,那么建议您进行测试以其他方式验证查询,以确保代码库发展时的数据完整性。
答案 1 :(得分: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"]);
}
正如Manu所说,你可以创建一个转换类,每个类型都有一个重载的转换方法,所以你不必用if / else块来编写你的代码。
但是我会强调,如果可以使用可空类型,那么它们是更好的选择。原因在于,对于非可空类型,您将不得不求助于“魔术数字”来表示null。例如,如果要将列映射到int变量,那么您将如何表示DBNull?通常你不能使用0,因为0在大多数程序中都有有效含义。我经常看到人们将DBNull映射到int.MinValue,但这也可能存在问题。我最好的建议是:
可以使用Nullable类型来解决这个问题。话虽这么说,如果您使用的是较旧版本的框架,或者为那些没有grok nullable类型的人工作,那么代码示例就可以解决问题。
答案 2 :(得分:8)
添加对System.Data.DataSetExtensions
的引用,增加了Linq对查询数据表的支持。
这就像是:
string value = (
from row in ds.Tables[0].Rows
select row.Field<string>(0) ).FirstOrDefault();
答案 3 :(得分:8)
我总是使用if / Else检查版本,只有三元运算符才能清楚,简洁,无问题。将所有内容保留在一行上,包括在列为空时指定默认值。
因此,假设一个名为“MyCol”的可以为空的Int32列,我们希望在列为空时返回-99,但如果该列不为null则返回整数值:
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"]);
答案 4 :(得分:5)
如果您可以控制返回结果的查询,则可以使用ISNULL()返回非空值,如下所示:
SELECT
ISNULL(name,'') AS name
,ISNULL(age, 0) AS age
FROM
names
如果您的情况可以容忍这些神奇值替换为NULL,那么采用这种方法可以解决整个应用中的问题而不会使代码混乱。
答案 5 :(得分: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
我认为这是你正在寻找的最佳实践
答案 6 :(得分:3)
值得一提的是,DBNull.Value.ToString()
等于String.Empty
您可以利用此优势:
DataRow row = ds.Tables[0].Rows[0];
string value = row["name"].ToString();
然而,这仅适用于Strings,对于其他所有我将使用linq方式或扩展方法。对于我自己,我写了一个小的扩展方法来检查DBNull,甚至通过Convert.ChangeType(...)
进行转换
int value = row.GetValueOrDefault<int>("count");
int value = row.GetValueOrDefault<int>("count", 15);
答案 7 :(得分:2)
通常在使用DataTables时,你必须处理这种情况,其中row字段可以是null或DBNull,通常我会这样处理:
string myValue = (myDataTable.Rows[i]["MyDbNullableField"] as string) ?? string.Empty;
'as'运算符为无效的强制转换返回null,比如DBNull为string,'??'回报 如果第一个为null,则为表达式右侧的术语。
答案 8 :(得分:1)
您也可以使用Convert.IsDBNull (MSDN)进行测试。
答案 9 :(得分:1)
我通常编写自己的ConvertDBNull类来包装内置的Convert类。如果值为DBNull,则它将返回null(如果是引用类型)或默认值(如果是值类型)。
例:
- ConvertDBNull.ToInt64(object obj)
返回Convert.ToInt64(obj)
,除非obj为DBNull,在这种情况下它将返回0.
答案 10 :(得分:1)
出于某种原因,我在对DBNull.Value进行检查时遇到了问题,所以我做了一些稍微不同的事情并利用了DataRow对象中的属性:
if (row.IsNull["fooColumn"])
{
value = string.Empty();
}
{
else
{
value = row["fooColumn"].ToString;
}
答案 11 :(得分:1)
摘要“使用System.DBNull进行AVOID。改为使用Nullable。”
这是我的两分钱(未经测试的代码:))
// 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的原因?
答案 12 :(得分:1)
答案 13 :(得分:0)
如果您担心在期望字符串时获取DBNull,一个选项是将DataTable中的所有DBNull值转换为空字符串。
这样做非常简单,但它会增加一些开销,尤其是在处理大型DataTable时。如果您有兴趣,请查看显示如何操作的link