.NET SqlDataReader Item[]与GetString(GetOrdinal())有何区别?

13

使用SqlDataReader类时,以下两种方式在功能上有什么区别(如果有的话):

(string) dataReader["MyFieldName"];

并且

dataReader.GetString(dataReader.GetOrdinal("MyFieldName"));

5个回答

15

除了类型转换问题之外,在单次调用中是没有其他问题的。索引器将调用DbDataReader.GetOrdinal,然后调用适当的Get方法以获取值(请注意,使用序数调用Get方法比使用字段名称的索引器更快)。

然而,这将每次都需要进行序数查找。如果你正在以只向前、只读的方式迭代一些记录(这正是DbDataReader实例的意图),那么可以通过仅在一次查找时进行来减少此查找的开销。

可以像这样做:

// Move to the first record.  If no records, get out.
if (!dataReader.Read()) return;

// Before the loop.  Can do this for any other fields being
// accessed in the loop as well.
int myFieldNameOrdinal = dataReader.GetOrdinal("MyFieldName");

// Process the records.  Remember, already on the first record, so
// use do/while here.
do
{
    // Do something with your field.
    Console.WriteLine(dataReader.GetString(myFieldNameOrdinal));
} while (dataReader.Read());

4

在处理空值时:

// Will throw an InvalidCastException 
// Exception Message will be "Unable to cast object of type System.DBNull
// to System.String 
(string) dataReader["MyFieldName"]; 

// Will throw a SqlNullValueException
// Exception Message will be "Data is Null. This method or property
// cannot be called on Null values."
dataReader.GetString(dataReader.GetOrdinal("MyFieldName"));

1
我撤销了最后一次编辑,因为原帖的问题是询问两个语句之间的功能差异- 这个答案强调了在处理空值时的区别,而编辑则展示了如何检查空值,我不认为这与原帖的问题有关。 - dugas

2

在第一种情况下,你需要强制类型转换,这对于值类型来说很不好看(会涉及到拆箱)。个人而言,我总是使用第二种方法,并且我建议你也这样做。


好的,在第一种情况下,肯定会有最后一分钟的拆箱。但是你确定在第二种情况下过程中没有任何类似的事情发生吗? - nawfal

1
//Well, we want to avoid the null exception issue entirely.
//Let's check for null first, before we try to use the value.

if( !dataReader.IsDBNull(dataReader.GetOrdinal("MyFieldName")))
{
//Store my data or use the value
string mystring=dataReader.GetString(dataReader.GetOrdinal("MyFieldName"));
}

偶然发现法是一种很棒的发现方法。


这里的元注释是什么意思?你是在试图回答这个问题吗? - Shog9

0
作为对casperOne的回答的替代方案,可以很容易地将序数查找减少为应用程序的生命周期一次。而且,不需要手动维护变量来记录每个索引。
下面的代码期望每个类只有一个查询,如果你想在一个类中处理多个查询,也是很容易实现的。
从一个字段开始:
static readonly ConcurrentDictionary<string, int> OrdinalMap = 
            new ConcurrentDictionary<string, int>();

然后更新您的访问代码,类似于:

reader.GetString(OrdinalMap.GetOrAdd("MyFieldName", reader.GetOrdinal))

现在,你拥有了一个线程安全的O(1)常数查找功能,而无需维护任何手动变量地图或常数用法映射,如果更改查询,则会导致世界崩溃。虽然这似乎并不重要,但为了清晰起见,由于 GetOrAdd 的行为,如果您同时执行多个查询,可能会多次执行 reader.GetOrdinal("MyFieldName"),但从所有意图上看,它可以被视为执行一次。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接