válida visual validar valida tipos tipo puede otros objeto net isdbnull error convertir conversión conversion c# datatable types nullable

visual - C#DBNull y tipos anulables-la forma más limpia de conversión



system dbnull error (8)

Tengo una DataTable, que tiene varias columnas. Algunas de esas columnas son nulables.

DataTable dt; // Value set. DataRow dr; // Value set. // dr["A"] is populated from T-SQL column defined as: int NULL

Entonces, ¿cuál es la forma más limpia de conversión de un valor en un DataRow a una variable que se puede anular?

Idealmente, podría hacer algo como:

int? a = dr["A"] as int?;

Editar : Resulta que PUEDE hacer esto, el efecto secundario es que si sus tipos de esquema no son enteros, entonces SIEMPRE va a regresar nulo. La respuesta de Ruben de usar dr.Field<int?>("A") asegura que las discrepancias de tipos no fallen silenciosamente. Esto, por supuesto, será recogido por pruebas unitarias exhaustivas.

En cambio, generalmente estoy escribiendo algo como:

int? a = dr["A"] != DBNull.Value ? (int)dr["A"] : 0;

Este es un montón de teclas más, pero lo más importante, hay más espacio para que alguien llene algo con una pulsación de tecla incorrecta. Sí, una prueba de unidad lo recogerá, pero prefiero pararlo por completo.

¿Cuál es el patrón más limpio y menos propenso a errores para esta situación?


¿Por qué no usar LINQ? Hace la conversión por ti.


Este es el propósito de la clase DataRowExtensions en .NET 3.5, que proporciona métodos estáticos Field<T> y SetField<T> para el tropezón de datos que SetField<T> (y que no SetField<T> ) entre los tipos DataRow y .NET.

int? fld = row.Field<int?>("ColumnA")

establecerá fld en null si row["ColumnA"] contiene DBNull.Value , a su valor si contiene un entero, y arroja una excepción si contiene algo más. Y en el camino de regreso,

row.SetField("ColumnA", fld);

hace lo mismo al revés: si fld contiene null , establece la row["ColumnA"] en DBNull.Value y, de lo contrario, lo establece en el valor de fld .

Hay sobrecargas de Field y SetField para todos los tipos de valores que admite DataRow (incluidos DataRow tipos que no admiten nulos), por lo que puede usar el mismo mecanismo para obtener y configurar campos independientemente de su tipo de datos.


Lo siguiente funcionaría de forma segura:

Recorte:

public static class SqlDataReaderEx { public static int TryParse(SqlDataReader drReader, string strColumn, int nDefault) { int nOrdinal = drReader.GetOrdinal(strColumn); if (!drReader.IsDbNull(nOrdinal)) return drReader.GetInt32(nOrdinal); else return nDefault; } }

Uso:

SqlDataReaderEx.TryParse(drReader, "MyColumnName", -1);


Métodos de extensión!

Algo como lo siguiente:

public static class DataRowExtensions { public static Nullable<T> GetNullableValue<T>(this DataRow row, string columnName) where T : struct { object value = row[columnName]; if (Convert.IsDBNull(value)) return null; return (Nullable<T>)value; } public static T GetValue<T>(this DataRow row, string columnName) where T : class { object value = row[columnName]; if (Convert.IsDBNull(value)) return null; return (T)value; } }

Úselo así:

int? a = dr.GetNullableValue<int>("A");

o

string b = dr.GetValue<string>("B");


El capítulo LINQ to DataSets de LINQ in Action es una buena lectura.

Una cosa que verás es el método de extensión Field<T> , que se usa de la siguiente manera:

int? x = dr.Field<int?>( "Field" );

O

int y = dr.Field<int?>( "Field" ) ?? 0;

O

var z = dr.Field<int?>( "Field" );


Chart.data = new List < int ?> (); Chart.data = (from DataRow DR in _dtChartData.Rows select(int ? )((DR[_ColumnName] == DBNull.Value) ? (int ? ) null : (int ? ) DR[_ColumnName])).ToList();


int? a = (int?)dr["A"]


public static object GetColumnValue(this DataRow row, string columnName) { if (row.Table.Columns.Contains(columnName)) { if (row[columnName] == DBNull.Value) { if (row.Table.Columns[columnName].DataType.IsValueType) { return Activator.CreateInstance(row.Table.Columns[columnName].DataType); } else { return null; } } else { return row[columnName]; } } return null; }

Para llamar a la función, podrías escribir

var dt = new DataTable(); dt.Columns.Add("ColumnName"); .... Add rows in Datatable. .... dt.Rows[0].GetColumnValue("ColumnName);