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

JC *_*bbs 8 c#

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

mrr*_*rrk 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
Run Code Online (Sandbox Code Playgroud)

或(在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;
}
Run Code Online (Sandbox Code Playgroud)

:O)


Tad*_*mas 7

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

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

  • 不确定为什么人们会投票给你 - 这是最好的解决方案 (4认同)
  • 是的,它确实.reader.GetSchemaTable()中每行的第一项.行是列名.ie reader.GetSchemaTable().行[0] [0]给出了第一个列名. (2认同)

adp*_*dox -4

您不能只测试 reader["field"] 是否为 null 或 DBNull,因为如果该列不在读取器中,则会引发 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;
    }
Run Code Online (Sandbox Code Playgroud)