我如何检查看看一个列是否存在于一个SqlDataReader对象?在我的数据访问层,我创建了一个为多个存储过程调用构建相同对象的方法。其中一个存储过程具有其他存储过程不使用的附加列。我想修改方法以适应各种情况。
我的应用程序是用c#编写的。
我如何检查看看一个列是否存在于一个SqlDataReader对象?在我的数据访问层,我创建了一个为多个存储过程调用构建相同对象的方法。其中一个存储过程具有其他存储过程不使用的附加列。我想修改方法以适应各种情况。
我的应用程序是用c#编写的。
当前回答
我认为你最好的办法是在你的DataReader上预先调用GetOrdinal("columnName"),并在列不存在的情况下捕获indexoutofranceexception。
实际上,让我们创建一个扩展方法:
public static bool HasColumn(this IDataRecord r, string columnName)
{
try
{
return r.GetOrdinal(columnName) >= 0;
}
catch (IndexOutOfRangeException)
{
return false;
}
}
Edit
好吧,这篇文章最近开始获得一些反对票,我不能删除它,因为它是公认的答案,所以我将更新它,并(我希望)尝试证明使用异常处理作为控制流的合理性。
另一种实现方法是循环遍历DataReader中的每个字段,并对要查找的字段名进行不区分大小写的比较。这将工作得非常好,实际上可能会比我上面的方法更好。当然,我绝不会在性能有问题的循环中使用上述方法。
我可以想到一种情况,在这种情况下,try/GetOrdinal/catch方法可以工作,而循环则不行。然而,这完全是一个假设的情况,所以这是一个非常站不住脚的理由。不管怎样,耐心听我说,看看你怎么想。
假设有一个数据库允许您对表中的列进行“别名”。想象一下,我可以定义一个表,它的列名为“EmployeeName”,但也给它一个别名“EmpName”,对其中任何一个名称进行选择都将返回该列中的数据。跟得上吗?
现在假设有一个ADO。NET提供程序,他们为它编写了一个IDataReader实现,其中考虑了列别名。
现在,dr.GetName(i)(在Chad的回答中使用)只能返回单个字符串,因此它必须只返回列上的一个“别名”。但是,GetOrdinal(“EmpName”)可以使用该提供程序字段的内部实现来检查每个列的别名,以查找您要查找的名称。
在这种假设的“别名列”情况下,try/GetOrdinal/catch方法将是确保检查结果集中列名的每个变体的唯一方法。
脆弱的吗?当然。但值得一想。老实说,我更希望在IDataRecord上有一个“官方的”HasColumn方法。
其他回答
这对我来说很管用:
public static class DataRecordExtensions
{
public static bool HasColumn(IDataReader dataReader, string columnName)
{
dataReader.GetSchemaTable().DefaultView.RowFilter = $"ColumnName= '{columnName}'";
return (dataReader.GetSchemaTable().DefaultView.Count > 0);
}
}
public static class DataRecordExtensions
{
public static bool HasColumn(this IDataRecord dr, string columnName)
{
for (int i=0; i < dr.FieldCount; i++)
{
if (dr.GetName(i).Equals(columnName, StringComparison.InvariantCultureIgnoreCase))
return true;
}
return false;
}
}
在控制逻辑中使用异常被认为是不好的做法,并且会带来性能损失。它还会将抛出的# exceptions错误消息发送给分析器,并帮助任何人设置调试器在抛出异常时中断。
GetSchemaTable()也是许多答案中的另一个建议。这不是检查字段是否存在的首选方法,因为它不是在所有版本中都实现的(它是抽象的,并且在dotnetcore的某些版本中抛出NotSupportedException)。GetSchemaTable在性能方面也是过度消耗的,因为如果您查看源代码,它是一个相当繁重的函数。
如果您经常使用循环遍历字段,则可能会对性能造成较小的影响,您可能需要考虑缓存结果。
下面的方法很简单,对我来说很有效:
bool hasMyColumn = (reader.GetSchemaTable().Select("ColumnName = 'MyColumnName'").Count() == 1);
public static bool DataViewColumnExists(DataView dv, string columnName)
{
return DataTableColumnExists(dv.Table, columnName);
}
public static bool DataTableColumnExists(DataTable dt, string columnName)
{
string DebugTrace = "Utils::DataTableColumnExists(" + dt.ToString() + ")";
try
{
return dt.Columns.Contains(columnName);
}
catch (Exception ex)
{
throw new MyExceptionHandler(ex, DebugTrace);
}
}
列。Contains不区分大小写。
下面是接受答案的一行LINQ版本:
Enumerable.Range(0, reader.FieldCount).Any(i => reader.GetName(i) == "COLUMN_NAME_GOES_HERE")