在迭代之前检测IDataReader是否包含某个字段

时间:2008-09-09 21:25:43

标签: c#

所以我使用IDataReader来保存一些业务对象,但我不知道在运行时究竟哪些字段会在读者中。任何不在阅读器中的字段都将在结果对象上保留为null。如何测试读者是否包含特定字段而不将其包装在try / catch中?

6 个答案:

答案 0 :(得分:9)

这应该可以解决问题:

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

:○)

答案 1 :(得分:7)

您还可以使用IDataReader.GetSchemaTable获取阅读器中所有列的列表。

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

答案 2 :(得分:4)

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

答案 3 :(得分:0)

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

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

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

答案 4 :(得分:-3)

虽然我不同意这种方法(我认为在访问数据时,你应该事先知道形状),但我知道有例外。

您总是可以使用阅读器加载数据表,然后迭代它。然后,您可以检查列是否存在。这样性能较差,但您不需要try / catch块(因此可能更符合您的需求)。

答案 5 :(得分:-4)

您不能仅仅为null或DBNull测试reader [“field”],因为如果列不在阅读器中,则抛出IndexOutOfRangeException。

我在映射层中用于创建域对象的代码和使用映射层的存储过程可能具有不同的列名,如下所示;如果找不到该列,则可以将其修改为不抛出异常并返回default(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;
    }