DataReader - 硬编码序数?

Dav*_*ale 15 .net c# datareader sqldatareader

DataReaderI 返回数据时,通常会使用序号引用DataReader来获取相关列:

if (dr.HasRows)         
   Console.WriteLine(dr[0].ToString());
Run Code Online (Sandbox Code Playgroud)

要么

if (dr.HasRows)         
   Console.WriteLine(dr.GetString(0));
Run Code Online (Sandbox Code Playgroud)

要么

if (dr.HasRows)         
   Console.WriteLine((string)dr[0]);
Run Code Online (Sandbox Code Playgroud)

我一直这样做是因为我在早期阶段被告知使用dr["ColumnName"]或更优雅的索引方式会导致性能下降.

然而,尽管对数据实体的所有引用都变得越来越强烈,但我对此感到更加不安.我也知道上面没有检查DBNull.

从数据库中返回数据最有效的方法是DataReader什么?

Mar*_*ins 25

在这种情况下,双方都有可能争论不休.正如其他人已经指出的那样,使用名称更具可读性,如果有人更改了底层数据库中列的顺序,则不会中断.但人们也可能会争辩说,如果某人更改了底层数据库中的列名,使用序数的优点是不会破坏.不过,我更喜欢前一个参数,并认为列名的可读性参数通常胜过第二个参数.名称的另一个论点是,它可以"自我检测"错误.如果有人确实更改了字段名称,那么代码有更好的破解机会,而不是在读取错误的字段时出现微妙的错误.

这似乎是显而易见的,但也许值得一提的是具有自检错误和序数性能的用例.如果在SQL中显式指定SELECT列表,那么使用序数将不会成为问题,因为代码中的语句保证了顺序:

SELECT name, address, phone from mytable
Run Code Online (Sandbox Code Playgroud)

在这种情况下,使用序数来访问数据是相当安全的.如果有人在表格中移动字段并不重要.如果有人更改了名称,那么SQL语句在运行时会产生错误.

最后一点.我刚刚对我帮助写的提供商进行了测试.测试读取100万行并访问每条记录上的"lastname"字段(与值进行比较).使用rdr[“lastname”]花费3301毫秒来处理rdr.GetString(1)2640毫秒(大约25%的加速).在此特定提供程序中,名称的查找使用排序查找将名称转换为序数.


Jos*_*osh 15

字符串名称查找比序数调用贵得多,但比硬编码序列更易于维护且更不"脆弱".所以这就是我一直在做的事情.这是两全其美的.如果列顺序发生变化,我不必记住序数值或关注,但是我获得了使用序数的性能优势.

var dr = command.ExecuteQuery();
if (dr.HasRows)
{
    //Get your ordinals here, before you run through the reader
    int ordinalColumn1 = dr.GetOrdinal("Column1");
    int ordinalColumn2 = dr.GetOrdinal("Column2");
    int ordinalColumn3 = dr.GetOrdinal("Column3");

    while(dr.Read())
    {
        // now access your columns by ordinal inside the Read loop. 
        //This is faster than doing a string column name lookup every time.
        Console.WriteLine("Column1 = " + dr.GetString(ordinalColumn1);
        Console.WriteLine("Column2 = " + dr.GetString(ordinalColumn2);
        Console.WriteLine("Column3 = " + dr.GetString(ordinalColumn3);
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:这对于你期望拥有相当数量的行的读者来说才真正有意义.这些GetOrdinal()调用是额外的,只有GetString(int ordinalNumber)在循环中调用的总节省量大于调用成本时才能自行支付GetOrdinal.

编辑:错过了这个问题的第二部分.关于DBNull值,我已经开始编写处理这种可能性的扩展方法.示例:dr.GetDatetimeSafely() 在这些扩展方法中,您可以做任何您需要的事情,以确保您获得预期的价值.