Невозможно передать объект типа "System.DBNull" для ввода "System.String"

Я получил вышеуказанную ошибку в своем приложении. Вот исходный код

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();
    }
}

Есть ли лучший способ обойти это?

Ответ 1

Можно использовать более короткую форму:

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

РЕДАКТИРОВАТЬ: Не обращали внимания на ExecuteScalar. Он действительно возвращает null, если поле отсутствует в возвращаемом результате. Поэтому используйте вместо этого:

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

Ответ 2

С простой общей функцией вы можете сделать это очень просто. Просто сделайте следующее:

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;
    }
}

Ответ 3

ExecuteScalar вернет

  • null, если нет набора результатов
  • в противном случае первый столбец первой строки набора результатов, который может быть DBNull.

Если вы знаете, что первый столбец набора результатов является строкой, то для охвата всех баз вам нужно проверить как null, так и DBNull. Что-то вроде:

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

Приведенный выше код основан на том факте, что DBNull.ToString возвращает пустую строку.

Если accountNumber был другим типом (скажем, integer), тогда вам нужно быть более явным:

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

Если вы точно знаете, что ваш набор результатов всегда будет содержать по крайней мере одну строку (например, SELECT COUNT (*)...), вы можете пропустить проверку нулевого значения.

В вашем случае сообщение об ошибке "Невозможно передать объект типа" System.DBNull для ввода "System.String" означает, что первый столбец вашего результирующего набора является значением DBNUll. Это от строки до строки в первой строке:

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

Комментарий Marc_s, что вам не нужно проверять наличие DBNull.Value неправильно.

Ответ 4

Вы можете использовать оператор С# null коалесцирования

return accountNumber ?? string.Empty;

Ответ 5

Существует другой способ обхода этой проблемы. Как насчет изменения вашей процедуры магазина? используя функцию ISNULL (ваше поле, "") sql, вы можете вернуть пустую строку, если возвращаемое значение равно null.

Затем у вас есть чистый код в качестве исходной версии.

Ответ 6

Это общий метод, который я использую для преобразования любого объекта, который может быть 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);

Ответ 7

Я полагаю, вы можете сделать это вот так:

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

Если accountNumber имеет значение null, это означает, что это DBNull не строка:)

Ответ 8

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);

 }

Однако, я думаю, что вы теряете что-то по понятности кода.

Ответ 9

Я использую расширение, чтобы устранить эту проблему для меня, что может быть или не быть тем, что вы после.

Это происходит следующим образом:

public static class Extensions
{

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

}

Примечание:

Это расширение не возвращает null значения! Если элемент null или DBNull.Value, он вернет пустую строку.

Использование:

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

Ответ 10

Преобразуйте его как

string s = System.DBNull.value.ToString();