Определение наличия в IDataReader определенного поля перед итерацией

Итак, я использую IDataReader для гидратации некоторых бизнес-объектов, но во время выполнения я не знаю, какие именно поля будут в считывателе. Любые поля, которых нет в средстве чтения, будут оставлены нулевыми в результирующем объекте. Как вы проверяете, содержит ли читатель определенное поле, не просто заключив его в команду try / catch?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
8
0
8 917
6

Ответы 6

Вы не можете просто проверить читатель ["field"] на null или DBNull, потому что генерируется исключение IndexOutOfRangeException, если столбец отсутствует в читателе.

Код, который я использую в своем слое отображения для создания объектов домена и хранимых процедур, которые используют слой сопоставления, может иметь разные имена столбцов, приведен ниже; вы можете изменить его, чтобы не создавать исключение, если столбец не найден, и возвращать значение по умолчанию (t) или null.

Я понимаю, что это не самое элегантное или оптимальное решение (и действительно, если вы можете этого избежать, то и должны), однако устаревшие хранимые процедуры или запросы Sql могут потребовать обходного пути.

    /// <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;
    }

Это будет плохо работать

DalSoft 24.07.2012 22:25

Хотя я не согласен с этим подходом (я думаю, что при доступе к данным вы должны знать форму заранее), я понимаю, что есть исключения.

Вы всегда можете загрузить данные с помощью ридера, а затем перебрать его. Затем вы можете проверить, существует ли столбец. Это будет менее производительно, но вам не понадобятся блоки try / catch (так что, возможно, он более эффективен для ваших нужд).

Это должно помочь:

    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

или (в 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)

Вы также можете использовать IDataReader.GetSchemaTable, чтобы получить список всех столбцов в считывателе.

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

GetSchemaTable не перечисляет столбцы возвращаемой структуры данных.

JamesEggers 13.08.2009 17:30

Да, это так. Первый элемент в каждой строке из reader.GetSchemaTable (). Строки - это имена столбцов. т.е. reader.GetSchemaTable (). Rows [0] [0] дает мне имя первого столбца.

Rob Levine 13.08.2009 17:40

В прошлый раз, когда я пробовал это, он дал мне столбцы типа schema_info. Мне придется попробовать еще раз, так как это было давно.

JamesEggers 13.08.2009 17:44

Не уверен, почему люди голосуют против вас - это лучшее решение

Jim Arnold 13.08.2009 17:55

Согласитесь с Джимом, легко лучшее решение

BenW 09.05.2012 12:07

Не уверен, что это самый лучший вариант. Контрастность reader.GetSchemaTable().Rows.Cast<DataRow>().Select(x => (string)x["ColumnName"]).Contains(colName, StringComparer.OrdinalIgnoreCase)сEnumerable.Range(0, reader.FieldCount).Select(reader.GetName).Contains(colName, StringComparer.OrdinalIgnoreCase). Подход FieldCount не только чище, но и во много раз быстрее.

nawfal 12.12.2013 18:30

Лучшее решение, которое я использовал, - это сделать так:

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

Попытка получить к нему доступ через читатель ["ColumnName"] и проверка на null или DBNull вызовет исключение.

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

Другие вопросы по теме