无法将类型为“ System.DBNull”的对象转换为类型为“ System.String”的对象


109

我的应用程式中出现上述错误。这是原始代码

public string GetCustomerNumber(Guid id)
{
     string accountNumber = 
          (string)DBSqlHelperFactory.ExecuteScalar(connectionStringSplendidmyApp, 
                          CommandType.StoredProcedure, 
                          "GetCustomerNumber", 
                          new SqlParameter("@id", id));
     return accountNumber.ToString();
 }

我换成

public string GetCustomerNumber(Guid id)
{
   object accountNumber =  
          (object)DBSqlHelperFactory.ExecuteScalar(connectionStringSplendidCRM, 
                                CommandType.StoredProcedure, 
                                "spx_GetCustomerNumber", 
                                new SqlParameter("@id", id));
    if (accountNumber is System.DBNull)
    {
       return string.Empty;
    }
    else
    {
       return accountNumber.ToString();
    }
}

有没有更好的办法解决这个问题?


2
您应该认真研究@rein的答案,从长远来看会为您节省很多时间
罗马

Answers:


89

可以使用较短的形式:

return (accountNumber == DBNull.Value) ? string.Empty : accountNumber.ToString()

编辑:尚未注意ExecuteScalar。如果返回结果中不存在该字段,则确实返回null。因此改用:

return (accountNumber == null) ? string.Empty : accountNumber.ToString() 

3
那是行不通的-“ accountNumber” 不是数据库值,而是常规的旧Plain .NET“对象”实例-您需要检查常规的“空”值。DBNull.Value适用于SqlDataReader或SqlParameter-但不适用于此对象。
marc_s

没错,我开始优化条件检查部分,之前没有看过这一行。Mea culpa。
用户

您的帖子中有我不能真正编辑的错字,因为编辑需要更改6个字符。有人可以将accountNumber.TosString()更改为accountNumber.ToString()
Eric

@marc_s根据数据库/查询的布局,您需要检查它们中的一个甚至两个。如果WHERE与任何行都不匹配null,则将获得,如果所选行在NULL该列中,则返回值为System.DBNull
亚历山大

在第一种情况下,@ Alexander提及-不匹配任何行-如果可以使用从null转换时返回的值,可以依靠Convert.ToString或任何其他Convert方法:空字符串表示字符串,数字值表示0,false用于布尔值,用于DateTime的MinValue ... msdn.microsoft.com/zh-cn/library/vstudio/…–
Jaime

199

使用简单的通用函数,您可以非常轻松地完成此操作。只是这样做:

return ConvertFromDBVal<string>(accountNumber);

使用功能:

public static T ConvertFromDBVal<T>(object obj)
{
    if (obj == null || obj == DBNull.Value)
    {
        return default(T); // returns the default value for the type
    }
    else
    {
        return (T)obj;
    }
}

1
是的,这样的功能是唯一可行的解​​决方案。复制和粘贴一千次后,任何形式的内联逻辑都将失败。:-)
Christian Hayter,2009年

3
如果您尝试将1转换为bool(Convert.ToBoolean(1)可以正常工作),这将不起作用
罗马m

@roman:因此,我们要进行一次额外的检查(在检查null之前),以检查布尔类型...
IAbstract 2010年

1
如果您想要或需要使用Convert函数,则此方法无效。在某些情况下,您可能希望转换为显式强制转换。@romanm注意到其中之一。另一个是当您使用小数并关注Convert.ToInt32和(int)使用的不同舍入机制时。前者四舍五入到最接近的偶数值,而显式转换只截断该值:stackoverflow.com/questions/1608801/…如果可能的话,我将使用T-SQL ISNULL函数从混合中消除NULL
Jaime

2
@Jaime该函数应该像从SQL数据类型隐式转换为C#/。NET数据类型一样。如果您需要显式强制转换,请不要使用此功能-而是显式执行。
控制2014年

17

ExecuteScalar将返回

  • 如果没有结果集,则为null
  • 否则,结果集第一行的第一列可能是DBNull。

如果您知道结果集的第一列是字符串,那么要覆盖所有基数,您需要检查null和DBNull。就像是:

object accountNumber = ...ExecuteScalar(...);
return (accountNumber == null) ? String.Empty : accountNumber.ToString();

上面的代码依赖于DBNull.ToString返回一个空字符串的事实。

如果accountNumber是另一种类型(例如整数),那么您需要更加明确:

object accountNumber = ...ExecuteScalar(...);
return (accountNumber == null || Convert.IsDBNull(accountNumber) ?     
         (int) accountNumber : 0;

如果您确定结果集将始终至少有一行(例如SELECT COUNT(*)...),则可以跳过对null的检查。

在您的情况下,错误消息“无法将类型为'System.DBNull'的对象转换为类型为'System.String'”表示结果集的第一列是DBNUll值。这是从第一行的强制转换为字符串:

string accountNumber = (string) ... ExecuteScalar(...);

Marc_s的注释,您不需要检查DBNull.Value是错误的。


我的结果集不会总是返回一行。
赛义夫汗2009年

6

您可以使用C#的空合并运算符

return accountNumber ?? string.Empty;

-1:无法编译:该方法返回一个字符串,而accountNumber是一个对象。

2
返回Cmd.ExecuteScalar()。ToString()?? String.Empty;
查塔尼亚

return Cmd.ExecuteScalar()。ToString()为我完成了工作
Taran

3

有另一种方法来解决此问题。如何修改您的存储过程?通过使用ISNULL(您的字段“”)sql函数,如果返回值为null,则可以返回空字符串。

然后,您可以将原始代码用作原始版本。


3

这是我用来转换任何可能是DBNull.Value的对象的通用方法:

public static T ConvertDBNull<T>(object value, Func<object, T> conversionFunction)
{
    return conversionFunction(value == DBNull.Value ? null : value);
}

用法:

var result = command.ExecuteScalar();

return result.ConvertDBNull(Convert.ToInt32);

较短:

return command
    .ExecuteScalar()
    .ConvertDBNull(Convert.ToInt32);

2

我想你可以这样:

string accountNumber = DBSqlHelperFactory.ExecuteScalar(...) as string;

如果accountNumber为null,则表示它是DBNull而不是string :)


或者return (accountNumber as string) ?? string.Empty;,accountNumber仍为object。如果您希望将数据库调用保持在自己的线路上。
布赖恩

1

String.Concat将DBNull和null值转换为空字符串。

public string GetCustomerNumber(Guid id)
{
   object accountNumber =  
          (object)DBSqlHelperFactory.ExecuteScalar(connectionStringSplendidCRM, 
                                CommandType.StoredProcedure, 
                                "spx_GetCustomerNumber", 
                                new SqlParameter("@id", id));

    return String.Concat(accountNumber);

 }

但是,我认为您在代码可理解性方面有所损失


1
如果写东西会return "" + accountNumber;怎样?
Zev Spitz 2014年

0

因为我有一个不为null的实例,并且如果我将其与DBNULL进行了比较,则得到了Operator '==' cannot be applied to operands of type 'string' and 'system.dbnull'证明,并且如果我尝试更改以与NULL进行比较,那么它根本就没有用(因为DBNull是一个对象),即使这是公认的答案。

我决定只使用'is'关键字。因此,结果非常可读:

data = (item is DBNull) ? String.Empty : item


-1

我使用扩展程序为我消除了此问题,无论您追求的是与否。

它是这样的:

public static class Extensions
{

    public String TrimString(this object item)
    {
        return String.Format("{0}", item).Trim();
    }

}

注意:

该扩展名返回null值!如果该项是nullDBNull.Value,它将返回一个空的String。

用法:

public string GetCustomerNumber(Guid id)
{
    var obj = 
        DBSqlHelperFactory.ExecuteScalar(
            connectionStringSplendidmyApp, 
            CommandType.StoredProcedure, 
            "GetCustomerNumber", 
            new SqlParameter("@id", id)
        );
    return obj.TrimString();
}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.