Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# DataReader-硬代码序号?_C#_.net_Sqldatareader_Datareader - Fatal编程技术网

C# DataReader-硬代码序号?

C# DataReader-硬代码序号?,c#,.net,sqldatareader,datareader,C#,.net,Sqldatareader,Datareader,从DataReader返回数据时,我通常会使用DataReader上的顺序引用来获取相关列: if (dr.HasRows) Console.WriteLine(dr[0].ToString()); 或 或 我总是这样做,因为在早期阶段,有人建议我使用dr[“ColumnName”]或更优雅的索引方式会导致性能下降 然而,当所有对数据实体的引用都变得越来越强类型化时,我对此感到更不舒服。我也知道上面没有检查DBNull 从数据读取器返回数据的最可靠方法是什么?与使用列名

DataReader
返回数据时,我通常会使用
DataReader
上的顺序引用来获取相关列:

if (dr.HasRows)         
   Console.WriteLine(dr[0].ToString());

我总是这样做,因为在早期阶段,有人建议我使用
dr[“ColumnName”]
或更优雅的索引方式会导致性能下降

然而,当所有对数据实体的引用都变得越来越强类型化时,我对此感到更不舒服。我也知道上面没有检查
DBNull


数据读取器
返回数据的最可靠方法是什么?

与使用列名不同,ordinal的问题是如果列的顺序发生变化,并且您被迫修改数据读取器的使用者代码


我不认为使用序号或列名会提高性能,更多的是在最佳实践、编码标准和代码可维护性方面。实际上,我总是使用字符串名方法,因为读取代码更干净。必须在心里解析到列名的索引是可怕的

我确实认为索引字段是更好的方法,如果它只是为了避免基础数据库中的字段名更改,这将需要重新编译应用程序,因为您硬编码了字段名

对于每个字段,都需要手动检查空值

var dr = command.ExecuteQuery();

if (dr.HasRows) {
    var customer = new Customer();
    // I'm assuming that you know each field's position returned from your query.
    // Where comes the importance to write all of your selected fields and not just "*" or "ALL".
    customer.Id = dr[0] == null || dr[0] == DBNull.Value ? null : Convert.ToInt32(dr[0]);
    ...
}

除此之外,它还允许您使用反射,并使这个“GetData()”方法更通用,提供一个typeof(T)并为适当的类型获取适当的构造函数。对每一列顺序的绑定是一些人希望避免的唯一一件事,但在这种情况下,它是值得的。

按名称对数据读取器进行索引稍微贵一些。这主要有两个原因

  • 典型的实现将字段信息存储在使用数字索引的数据结构中。必须进行映射操作才能将名称转换为数字
  • 一些实现将对名称进行两次查找。第一步尝试在启用区分大小写的情况下匹配字段名。如果该过程失败,则第二个过程将从关闭区分大小写开始
但是,在大多数情况下,按名称查找字段所产生的性能损失与数据库执行命令所需的时间相比相形见绌。不要让性能损失决定您在名称索引和数字索引之间的选择

尽管有轻微的性能损失,我通常选择名称索引有两个原因

  • 代码更容易阅读
  • 代码对resultset模式中的更改更为宽容

如果您觉得名称索引的性能损失变得有问题(可能命令执行得很快,但返回了很多行),那么请按名称查找数字索引一次,将其保存起来,并将其用于其余的行。

字符串名称查找比序数调用要昂贵得多,但更易于维护,成本更低“脆弱”比硬编码序数更重要。我就是这样做的。这两个方面都是最好的。我不必记住序数值,也不必关心列顺序是否改变,但使用序数会带来性能上的好处

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);
    }
}
注意:这只对您希望有相当数量的行的读者才有意义。
GetOrdinal()
调用是额外的,只有在循环中调用
GetString(int-ordinalNumber)
所节省的总成本大于调用
GetOrdinal
的成本时,才会为自己付费


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

在这种情况下,双方都有可能争论。正如其他人已经指出的,使用该名称更具可读性,并且在有人更改基础数据库中的列顺序时不会中断。但是可能会有人这样做还有一种情况是,如果有人更改基础数据库中的列名,使用序数的好处是不会中断。不过,我更喜欢前一个参数,并且认为列名的可读性参数一般优于第二个参数。名称的另一个参数是它可以“自我检测”错误。如果有人确实更改了字段名,那么代码更有可能被破坏,而不是在读取错误字段时出现细微的错误

这似乎很明显,但可能值得一提的是一个既有自检测错误又有序号性能的用例。如果在SQL中显式指定SELECT列表,则使用序号不会有问题,因为代码中的语句保证了顺序:

SELECT name, address, phone from mytable
在这种情况下,使用序号访问数据是相当安全的。如果有人在表中移动字段,这并不重要。如果有人更改名称,SQL语句在运行时会产生错误


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

使用列名可消除“幻数”“同时也使程序员的工作更容易。使用序号是一种过早的微观优化。这个问题有两个部分,性能方面和可维护性/可读性。”
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);
    }
}
SELECT name, address, phone from mytable