2009-07-30 7 views
37

¿Hay alguna forma de ver si existe un campo en un objeto basado en IDataReader sin comprobar si hay una excepción IndexOutOfRangeException?Comprobación para ver si existe una columna en un lector de datos

En esencia, tengo un método que toma un objeto basado en IDataReader y crea una lista fuertemente tipada de los registros. En 1 instancia, un lector de datos tiene un campo que otros no. Realmente no quiero volver a escribir todas las consultas que alimentan este método para incluir alguna forma de este campo si no es necesario. La única forma en que he podido descifrar cómo hacerlo hasta el momento es arrojar el único campo 1 en un bloque try/catch como se muestra a continuación.

try 
{ 
    tmp.OptionalField = reader["optionalfield"].ToString(); 
} 
catch (IndexOutOfRangeException ex) 
{ 
    //do nothing 
} 

¿Hay una manera más limpia corta de añadir el "campo opcional" a las otras consultas o copiar el método de carga por lo que la versión 1 utiliza el campo opcional y el otro no lo hace?

Estoy en el marco 2.0 también.

+1

me pregunto por qué MS no ha añadido esta función para DataReader – FLICKER

Respuesta

52

Terminé encontrando una solución usando el método reader.GetName(int). Creé el siguiente método para abarcar la lógica.

public bool ColumnExists(IDataReader reader, string columnName) 
{ 
    for (int i = 0; i < reader.FieldCount; i++) 
    { 
     if (reader.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase)) 
     { 
      return true; 
     } 
    } 

    return false; 
} 
+8

puede mejorar la instrucción if: if (reader.GetName (i) .Equals (columnName, StringComparison.InvariantCultureIgnoreCase)) – Brabbeldas

+0

¿Qué sucede si se utiliza un alias? La comparación será incorrecta en ese caso seguramente? – Murphybro2

6

Aparece Ser corregido. I sepa sus nombres de columna reales están allí, pero estaba yendo por el camino equivocado. This reference ayudó a aclarar un poco las cosas, pero todavía no estoy seguro de si hay una manera elegante de hacerlo. Adaptado del enlace anterior, se puede obtener una lista de todas las columnas con la siguiente:

List<string> myCols = new List<string>(); 
DataTable schema = reader.GetSchemaTable(); 
foreach (DataRow row in schema.Rows) 
{ 
    myCols.Add(row[schema.Columns["ColumnName"]]); 
} 

Desafortunadamente parece que puede sólo schema.Rows acceso por índice, así que no estoy seguro de que puede moverse recorriendo las filas primero antes de verificar por nombre. En ese caso, ¡su solución original parece mucho más elegante!

Nota: mi respuesta original sugirió verificar la presencia de una columna simplemente por: reader.GetSchemaTable(). Columnas ["optionalfield"].

+0

Después de mirar más profundamente en GetSchemaTable(), parece que se está metadatos de columna completamente diferentes y no la tabla subyacente. Se presentan columnas como IsColumnSet y ColumnSize y no los campos reales. – JamesEggers

+0

Puede encontrar una lista de las columnas que obtengo en la lista de esta página: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.getschematable% 28VS.80% 29.aspx – JamesEggers

3

cargarlo en un DataTable y luego se puede comprobar si la columna:

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

No necesito tanto complicación, simplemente esto:

bool bFieldExists = datareader.GetSchemaTable().Columns.Contains(strFieldName); 
+4

Desafortunadamente, las "Columnas" en ese contexto son las columnas de metadatos sobre el IDataReader, no la lista de columnas de IDataReader. Cada fila dentro de GetSchemaTable() DataTable es una columna en el lector de datos. – JMD

+0

si no está restringido a .net 2.0, entonces podría hacer esto: bool bFieldExists = datareader.GetSchemaTable(). Columns.Select (o => o.Name) .Contains (myColumnName); – pqsk

5

Esto debería funcionar, intente esto:

private static bool ColumnExists(SqlDataReader reader, string columnName) 
     { 
      using (var schemaTable = reader.GetSchemaTable()) 
      { 
       if (schemaTable != null) 
        schemaTable.DefaultView.RowFilter = String.Format("ColumnName= '{0}'", columnName); 

       return schemaTable != null && (schemaTable.DefaultView.Count > 0); 
      } 
     } 
18

Lo siguiente dará usted una lista de las cadenas de nombre de columna dadas a un lector de datos. (Recuerde que los resultados se basan en la última lectura, por lo que puede no ser el mismo según lo que lea el lector).

var cols = reader.GetSchemaTable() 
       .Rows 
       .OfType<DataRow>() 
       .Select(row => row["ColumnName"]); 

o para comprobar si existe una columna:

public bool ColumnExists(IDataReader reader, string columnName) 
{ 

    return reader.GetSchemaTable() 
       .Rows 
       .OfType<DataRow>() 
       .Any(row => row["ColumnName"].ToString() == columnName); 
} 
+0

Esto utiliza LINQ que requiere .NET 3.5 o posterior. No funciona en .NET 2.0, que OP dijo que estaba usando. – Scott

+1

ColumnExists 'es una buena función. Sin embargo, tenga en cuenta que, como está escrito anteriormente, el código de ejemplo está roto. Debe agregar un lanzamiento explícito a la comparación, de lo contrario, utiliza una comparación de referencia y siempre devuelve falso. .Any (row => (String) row ["ColumnName"] == columnName); –

6
Enumerable.Range(0, reader.FieldCount).Any(i => reader.GetName(i) == "ColumnName") 
+1

Esto utiliza Linq que requiere .NET 3.5 o posterior. No funciona en .NET 2.0, que OP dijo que estaba usando. – Scott

Cuestiones relacionadas