No se puede convertir un objeto de tipo 'System.DBNull' para escribir 'System.String`
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?
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;
}
}
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()
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.
Puede utilizar el operador coalescente nulo de C#
return accountNumber ?? string.Empty;
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);