关于c#:在迭代之前检测IDataReader是否包含某个字段

关于c#:在迭代之前检测IDataReader是否包含某个字段

Detecting if an IDataReader contains a certain field before iteration

本问题已经有最佳答案,请猛点这里访问。

因此,我正在使用IDataReader合并一些业务对象,但是我不知道运行时究竟是哪个字段在阅读器中。 读取器中没有的任何字段在结果对象上都将保留为null。 您如何测试读者是否包含特定字段而不只是将其包装在try / catch中?


这应该可以解决问题:

1
2
3
4
5
6
    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#中)

1
2
3
4
5
6
7
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


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

我使用过的最好的解决方案是这样做的:

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

尝试通过reader [" ColumnName"]访问它并检查null或DBNull将引发异常。


尽管我不同意这种方法(我认为在访问数据时应该先了解形状),但我知道也有例外。

您总是可以使用读取器加载数据表,然后对其进行遍历。然后,您可以检查该列是否存在。这会降低性能,但是您不需要try / catch块(因此也许可以满足您的需求)。


您不能只测试reader [" field"]是否为null或DBNull,因为如果列不在阅读器中,则会抛出IndexOutOfRangeException。

我在映射层中使用的用于创建域对象的代码以及使用该映射层的存储过程可能具有不同的列名,如下所示;您可以对其进行修改,以便在找不到该列时不引发异常,并返回default(t)或null。

我知道这不是最优雅或最佳的解决方案(实际上,如果可以避免,那么应该这样做),但是,旧式存储过程或Sql查询可能需要解决方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
    /// <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;
    }


推荐阅读