No se puede convertir un objeto de tipo 'System.DBNull' para escribir 'System.String`

Resuelto Saif Khan asked hace 15 años • 13 respuestas

Recibí el error anterior en mi aplicación. Aquí está el código original.

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

lo reemplacé con

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 una mejor manera de solucionar esto?

Saif Khan avatar May 16 '09 03:05 Saif Khan
Aceptado

Con una función genérica simple puedes hacer esto muy fácil. Sólo haz esto:

return ConvertFromDBVal<string>(accountNumber);

usando la función:

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;
    }
}
rein avatar May 15 '2009 20:05 rein

Se puede utilizar una forma más corta:

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

EDITAR: No le he prestado atención ExecuteScalar. Realmente devuelve nulo si el campo está ausente en el resultado devuelto. Entonces usa en su lugar:

return (accountNumber == null) ? string.Empty : accountNumber.ToString() 
User avatar May 15 '2009 20:05 User

ExecuteScalar volverá

  • nulo si no hay ningún conjunto de resultados
  • de lo contrario, la primera columna de la primera fila del conjunto de resultados, que puede ser DBNull.

Si sabe que la primera columna del conjunto de resultados es una cadena, para cubrir todas las bases debe verificar tanto null como DBNull. Algo como:

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

El código anterior se basa en el hecho de que DBNull.ToString devuelve una cadena vacía.

Si accountNumber fuera de otro tipo (por ejemplo, un número entero), entonces tendría que ser más explícito:

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

Si está seguro de que su conjunto de resultados siempre tendrá al menos una fila (por ejemplo, SELECT COUNT(*)...), entonces puede omitir la verificación de nulo.

En su caso, el mensaje de error "No se puede convertir el objeto de tipo 'System.DBNull' al tipo 'System.String`" indica que la primera columna de su conjunto de resultados es un valor DBNUll. Esto es del elenco a la cadena en la primera línea:

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

El comentario de Marc_s de que no es necesario verificar DBNull.Value es incorrecto.

Joe avatar May 15 '2009 20:05 Joe

Puede utilizar el operador coalescente nulo de C#

return accountNumber ?? string.Empty;
Nathan Koop avatar May 15 '2009 20:05 Nathan Koop

Este es el método genérico que utilizo para convertir cualquier objeto que pueda ser DBNull.Value:

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

uso:

var result = command.ExecuteScalar();

return result.ConvertDBNull(Convert.ToInt32);

corta:

return command
    .ExecuteScalar()
    .ConvertDBNull(Convert.ToInt32);
Joep Geevers avatar Mar 01 '2016 11:03 Joep Geevers