2009-07-30 22 views
37

Czy istnieje sposób sprawdzenia, czy pole istnieje w obiekcie opartym na IDataReader bez sprawdzania indeksu IndexOutOfRangeException?Sprawdzanie, czy kolumna istnieje w czytniku danych

W istocie mam metodę, która pobiera obiekt oparty na IDataReader i tworzy listę wpisów z silnym typem. W jednym przypadku jeden czytnik danych ma pole, którego inni nie. Naprawdę nie chcę przepisywać wszystkich zapytań, które zasilają tę metodę, aby zawrzeć jakąś formę tego pola, jeśli nie muszę. Jedyny sposób, w jaki udało mi się wymyślić, jak to zrobić, to rzucić jedno unikalne pole do bloku prób/catch, jak pokazano poniżej.

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

Czy istnieje przejrzysty sposób krótki dodawania „opcjonalne pole” do innych zapytań lub kopiowanie metodę ładowania tak 1 wersja wykorzystuje pole opcjonalne, a inne nie?

Jestem również w ramach 2.0.

+1

Zastanawiam się dlaczego MS nie został dodany tej funkcji DataReader – FLICKER

Odpowiedz

52

Skończyło się na znalezieniu rozwiązania przy użyciu metody reader.GetName(int). Stworzyłem poniższą metodę, aby objąć logikę.

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

można ulepszyć instrukcję if: if (read.GetName (i) .Equals (columnName, StringComparison.InvariantCultureIgnoreCase)) – Brabbeldas

+0

Co zrobić, jeśli używany jest alias? Porównanie będzie w tym przypadku z pewnością błędne? – Murphybro2

6

Pojawia się, poprawiam stan. I znam twoje rzeczywiste nazwy kolumn są tam, ale szedłem złą ścieżką. This reference pomógł trochę oczyścić, ale nadal nie jestem pewien, czy jest to elegancki sposób. Zaczerpnięte z powyższego linku, można uzyskać listę wszystkich kolumn z następujących czynności:

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

Niestety wydaje się, można tylko schema.Rows dostępu przez indeks, więc nie jestem pewien, że można obejść najpierw przechodzenie przez rzędy przed sprawdzeniem przez nazwę. W takim przypadku oryginalne rozwiązanie wydaje się dużo bardziej eleganckie!

Uwaga: moja oryginalna odpowiedź sugerowała sprawdzenie obecności kolumny po prostu przez: reader.GetSchemaTable(). Columns ["optionalfield"].

+0

Po patrząc głębiej GetSchemaTable(), wydaje się, aby uzyskać całkowicie różne metadane kolumny, a nie tabelę podstawową. Przedstawione są kolumny takie jak IsColumnSet i ColumnSize, a nie rzeczywiste pola. – JamesEggers

+0

Lista kolumn, które otrzymuję, znajduje się na liście na tej stronie: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldatareader.getschematable% 28VS.80% 29.aspx – JamesEggers

3

załadować je do DataTable, a następnie można sprawdzić w kolumnie:

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

nie trzeba tak wiele komplikacji, po prostu tak:

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

Niestety "Kolumny" w tym kontekście są kolumnami metadanych dotyczących obiektu IDataReader, a nie listy kolumn IDataReadera. Każdy wiersz w tabeli GetSchemaTable() Data jest kolumną w DataSeradera. – JMD

+0

jeśli nie jesteś ograniczony do .net 2.0, to możesz to zrobić: bool bFieldExists = datareader.GetSchemaTable(). Columns.Select (o => o.Name) .Contains (myColumnName); – pqsk

5

To powinno działać, spróbuj to:

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

Następujące da masz listę ciągów nazw kolumn podanych w czytniku danych. (Pamiętaj, że wyniki są oparte na ostatnim czytaniu, więc może nie być to taki sam w zależności od tego, co czytał czytelnik).

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

lub w celu sprawdzenia, czy istnieje kolumna:

public bool ColumnExists(IDataReader reader, string columnName) 
{ 

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

To wykorzystuje LINQ, który wymaga .NET 3.5 lub nowszego. Nie działa na .NET 2.0, który OP powiedział, że był przy użyciu. – Scott

+1

ColumnExists "to fajna funkcja. Pamiętaj jednak, że napisany powyżej przykładowy kod jest zepsuty. Do porównania należy dodać jawną obsadę, w przeciwnym razie używa porównania odniesienia i zawsze zwraca wartość false. . Any (wiersz => (ciąg) wiersz ["ColumnName"] == columnName); –

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

Używa Linq, która wymaga .NET 3.5 lub nowszej. Nie działa na .NET 2.0, który OP powiedział, że był przy użyciu. – Scott