Não é possível converter o object do tipo ‘System.DBNull’ para digitar ‘System.String’

Eu tenho o erro acima no meu aplicativo. Aqui está o código original

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

Substituí com

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

Existe uma maneira melhor de contornar isso?

Um formulário mais curto pode ser usado:

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

EDIT: não prestou atenção ao ExecuteScalar. Realmente retorna null se o campo estiver ausente no resultado de retorno. Então use em vez disso:

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

Com uma function genérica simples, você pode tornar isso muito fácil. Apenas faça isso:

 return ConvertFromDBVal(accountNumber); 

usando a function:

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

ExecuteScalar retornará

  • null se não houver conjunto de resultados
  • caso contrário, a primeira coluna da primeira linha do conjunto de resultados, que pode ser DBNull.

Se você sabe que a primeira coluna do conjunto de resultados é uma string, então, para cobrir todas as bases, é necessário verificar tanto o valor nulo quanto o DBNull. Algo como:

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

O código acima depende do fato de que DBNull.ToString retorna uma seqüência vazia.

Se accountNumber fosse outro tipo (digamos, integer), você precisaria ser mais explícito:

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

Se você tiver certeza de que seu conjunto de resultados sempre terá pelo menos uma linha (por exemplo, SELECT COUNT (*) …), você pode pular a verificação para null.

No seu caso, a mensagem de erro “Não é possível converter object do tipo ‘System.DBNull’ para digitar ‘System.String`” indica que a primeira coluna do seu conjunto de resultados é um valor DBNUll. Isso é do casting para string na primeira linha:

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

O comentário de Marc_s de que você não precisa verificar DBNull.Value está errado.

Você pode usar o operador de coalescência nulo do C #

 return accountNumber ?? string.Empty; 

Existe outra maneira de contornar esse problema. Como sobre modificar seu procedimento de loja? usando a function sql ISNULL (seu campo, “”), você pode retornar uma string vazia se o valor de retorno for nulo.

Então você tem seu código limpo como versão original.

Este é o método genérico que utilizo para converter qualquer object que possa ser um DBNull.Value:

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

uso:

 var result = command.ExecuteScalar(); return result.ConvertDBNull(Convert.ToInt32); 

mais curta:

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

Eu suponho que você pode fazer assim:

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

Se accountNumber for null, significa que DBNull não foi string 🙂

String.Concat transforma valores DBNull e null em uma string vazia.

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

No entanto, acho que você perde algo na compreensão do código

Desde que eu tenho uma instância que não é nulo e se eu comparou a DBNULL eu tenho Operator '==' cannot be applied to operands of type 'string' and 'system.dbnull' exeption, e se eu tentei mudar para comparar NULL, simplesmente não funcionou (desde DBNull é um object) mesmo que seja a resposta aceita.

Eu decidi simplesmente usar a palavra-chave ‘is’. Então o resultado é muito legível:

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

Eu uso uma extensão para eliminar esse problema para mim, que pode ou não ser o que você está procurando.

É assim:

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

Nota:

Esta extensão não retorna valores null ! Se o item for null ou DBNull.Value , ele retornará uma String vazia.

Uso:

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

Converta-o como

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