【问题标题】:Checking to see if a column exists in a data reader [duplicate]检查数据读取器中是否存在列[重复]
【发布时间】:2009-07-30 13:26:15
【问题描述】:

有没有一种方法可以查看一个字段是否存在于基于 IDataReader 的对象中,而无需检查 IndexOutOfRangeException?

本质上,我有一个方法,它接受一个基于 IDataReader 的对象并创建一个强类型的记录列表。在一种情况下,一个数据读取器具有其他人没有的字段。如果我不需要的话,我真的不想重写所有提供此方法的查询以包含该字段的某种形式。到目前为止,我能够弄清楚如何做到这一点的唯一方法是将 1 个唯一字段放入 try/catch 块中,如下所示。

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

除了将“可选字段”添加到其他查询或复制加载方法以使 1 个版本使用可选字段而另一个不使用之外,还有更简洁的方法吗?

我也在2.0框架中。

【问题讨论】:

  • 我想知道为什么MS没有在DataReader中添加这个功能

标签: c# idatareader


【解决方案1】:

我最终找到了使用reader.GetName(int) 方法的解决方案。我创建了以下方法来包含逻辑。

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

【讨论】:

  • 你可以改进 if 语句:if (reader.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase))
  • 如果使用别名怎么办?在那种情况下,比较肯定是不正确的吗?
【解决方案2】:

下面将为您提供给定数据读取器的列名字符串列表。 (请记住,结果基于最后一次阅读,因此可能会因阅读者阅读的内容而异)。

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

或检查列是否存在:

public bool ColumnExists(IDataReader reader, string columnName)
{

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

【讨论】:

  • 这使用需要 .NET 3.5 或更高版本的 LINQ。不适用于 OP 说他正在使用的 .NET 2.0。
  • ColumnExists' 是一个不错的功能。但请注意,如上所述,示例代码已损坏。您必须在比较中添加显式强制转换,否则它使用引用比较并始终返回 false。 .Any(row => (String)row["ColumnName"] == columnName);
【解决方案3】:
Enumerable.Range(0, reader.FieldCount).Any(i => reader.GetName(i) == "ColumnName")

【讨论】:

  • 这使用需要 .NET 3.5 或更高版本的 Linq。不适用于 OP 说他正在使用的 .NET 2.0。
【解决方案4】:

这应该可行,试试这个:

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

【讨论】:

    【解决方案5】:

    看来我的立场是正确的。我知道您的实际列名在那里,但我走错了路。 This reference 帮助解决了一些问题,但我仍然不确定是否有一种优雅的方式来做这件事。改编自上面的链接,您可以获得所有列的列表,其中包含以下内容:

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

    不幸的是,您似乎只能按索引访问 schema.Rows,所以我不确定您是否可以先遍历行,然后再按名称检查。在这种情况下,您原来的解决方案似乎更加优雅!

    注意:我最初的回答建议通过 reader.GetSchemaTable().Columns["optionalfield"] 来检查列是否存在。

    【讨论】:

    • 在深入研究 GetSchemaTable() 之后,它似乎获得了完全不同的列元数据,而不是基础表。显示的是 IsColumnSet 和 ColumnSize 等列,而不是实际的字段。
    • 我正在获取的列列表可以在此页面的列表中找到:msdn.microsoft.com/en-us/library/…
    【解决方案6】:

    将其加载到 DataTable 中,然后您可以检查列:

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

    【讨论】:

      【解决方案7】:

      不需要这么复杂,就这个:

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

      【讨论】:

      • 不幸的是,该上下文中的“列”是有关 IDataReader 的元数据列,而不是 IDataReader 的列列表。 GetSchemaTable() DataTable 中的每一行都是 datareader 中的一列。
      • 如果您不限于 .net 2.0,那么您可以这样做: bool bFieldExists = datareader.GetSchemaTable().Columns.Select(o => o.Name).Contains(myColumnName );
      • 它不起作用
      • datareader.GetSchemaTable().Columns.Select(o => o.Name).Contains(myColumnName);这也不起作用
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-12-31
      • 2020-09-14
      • 2018-06-19
      • 2018-03-05
      • 2013-05-11
      • 2023-03-09
      • 1970-01-01
      相关资源
      最近更新 更多