2008-09-09 16 views
8

Así que estoy usando un IDataReader para hidratar algunos objetos comerciales, pero no sé en tiempo de ejecución qué campos exactamente estarán en el lector. Cualquier campo que no esté en el lector se dejará nulo en el objeto resultante. ¿Cómo se prueba si un lector contiene un campo específico sin simplemente envolverlo en un try/catch?Detectando si un IDataReader contiene un cierto campo antes de la iteración

Respuesta

-4

No se puede simplemente probar el lector ["field"] para null o DBNull porque se lanza IndexOutOfRangeException si la columna no está en el lector.

El código que uso en mi capa de mapeo para crear objetos de dominio y los procedimientos almacenados que usan la capa de mapeo pueden tener diferentes nombres de columna; puedes modificarlo para que no genere una excepción si la columna no se encuentra y devuelve el valor predeterminado (t) o nulo.

Entiendo que esta no es la solución más elegante u óptima (y en realidad, si puede evitarla, entonces debería hacerlo), sin embargo, los procedimientos almacenados heredados o las consultas Sql pueden garantizar una solución alternativa.

/// <summary> 
    /// Grabs the value from a specific datareader for a list of column names. 
    /// </summary> 
    /// <typeparam name="T">Type of the value.</typeparam> 
    /// <param name="reader">Reader to grab data off of.</param> 
    /// <param name="columnNames">Column names that should be interrogated.</param> 
    /// <returns>Value from the first correct column name or an exception if none of the columns exist.</returns> 
    public static T GetColumnValue<T>(IDataReader reader, params string[] columnNames) 
    { 
     bool foundValue = false; 
     T value = default(T); 
     IndexOutOfRangeException lastException = null; 

     foreach (string columnName in columnNames) 
     { 
      try 
      { 
       int ordinal = reader.GetOrdinal(columnName); 
       value = (T)reader.GetValue(ordinal); 
       foundValue = true; 
      } 
      catch (IndexOutOfRangeException ex) 
      { 
       lastException = ex; 
      } 
     } 

     if (!foundValue) 
     { 
      string message = string.Format("Column(s) {0} could not be not found.", 
       string.Join(", ", columnNames)); 

      throw new IndexOutOfRangeException(message, lastException); 
     } 

     return value; 
    } 
+1

Que funcionará mal – DalSoft

-3

Si bien estoy de acuerdo con este enfoque (creo que al acceder a datos, usted debe saber la forma antes de la mano), entiendo que hay excepciones.

Siempre se puede cargar una tabla de datos con el lector y luego iterar a través de él. Luego puede verificar si la columna existe. Esto será menos eficiente, pero no necesitará probar/atrapar bloques (por lo que tal vez sea más eficiente para sus necesidades).

9

Esto debería hacer el truco:

Public Shared Function ReaderContainsColumn(ByVal reader As IDataReader, ByVal name As String) As Boolean 
     For i As Integer = 0 To reader.FieldCount - 1 
      If reader.GetName(i).Equals(name, StringComparison.CurrentCultureIgnoreCase) Then Return True 
     Next 
     Return False 
    End Function 

o (en C#)

public static bool ReaderContainsColumn(IDataReader reader, string name) 
{ 
    for (int i = 0; i < reader.FieldCount; i++) { 
     if (reader.GetName(i).Equals(name, StringComparison.CurrentCultureIgnoreCase)) return true; 
    } 
    return false; 
} 

: o)

7

Puede también utilizar IDataReader.GetSchemaTable para obtener una lista de todas las columnas de el lector.

http://support.microsoft.com/kb/310107

+0

GetSchemaTable no muestra las columnas de la estructura de datos devuelta. – JamesEggers

+2

Sí lo hace. El primer elemento de cada fila del lector. GetSchemaTable(). Las filas son los nombres de las columnas. es decir, reader.GetSchemaTable(). Filas [0] [0] me da el primer nombre de columna. –

+0

La última vez que lo intenté, me dieron las columnas de schema_info. Aunque tendré que volver a intentarlo, ya que ha pasado un tiempo. – JamesEggers

0

La mejor solución que he usado está haciendo de esta manera:

DataTable dataTable = new DataTable(); 
dataTable.Load(reader); 
foreach (var item in dataTable.Rows) 
{ 
    bool columnExists = item.Table.Columns.Contains("ColumnName"); 
} 

Tratar de acceder a él a través lector [ "ColumnName"] y la comprobación de DBNull nulo o arrojará una excepción.

4
Enumerable.Range(0, reader.FieldCount).Any(i => reader.GetName(i) == "ColumnName") 
Cuestiones relacionadas