通用 DataReader 代码示例 (.net)

Posted

技术标签:

【中文标题】通用 DataReader 代码示例 (.net)【英文标题】:Example of generic DataReader code (.net) 【发布时间】:2009-11-06 01:49:16 【问题描述】:

由于我的 .Net 经验真正开始于为一家公司处理现有的内部应用程序,我觉得我在不知不觉中学会了许多糟糕的编码实践。我拼命试图继续前进的一个是DataSets用于一切。 (我确实知道强类型数据集在那里,它们肯定有一些用途......但在大多数情况下不是这样,例如选择数据)

我正在为通用数据库工作建立一个“助手”类...我有一个返回数据表的方法(用于选择等),我猜默认情况下(以及书籍/在线中的大多数示例) 将使用 DataAdapter 的 Fill 方法,但肯定是为了提高性能,想用读取所有行然后关闭的数据读取器替换它……我猜这是 Fill 方法在下面的工作原理……但我会如果大型结果集的性能可能会受到影响,则不要简单地采用懒惰的方式。

无论如何,我这辈子都找不到一个 dataReader 被用来一般地填充数据表的例子......我相信会有好的和坏的例子,因此一个公认的最佳实践如何来执行这样的任务。此类代码的链接(甚至是帖子)会很棒!我主要是 VB.Net,但 c# 没有障碍。

注意:对不起,如果这听起来也很懒惰,我只是想这种例子会到处张贴......不需要重新发明***等。谢谢!

【问题讨论】:

学习如何使用 DataReader 并没有什么坏处,但就性能而言,除非您能找到可证明的问题,否则您最好坚持使用经过试验和测试的 DataAdapter。没有具体要求的过早优化是不好的做法。 在需要之前进行优化的优点,我很感激。不过我想,由于使用 DataReader(从我读过的内容)具有经过验证的性能提升(特别是随着行数的增加),因此确实需要至少提供一种通用方法来选择何时行数是预计会很大。 【参考方案1】:

您找不到用于一般填充DataTableDataReader 示例的原因是因为您可以使用DataSet 中的Fill() 方法执行相同的操作,因此您只需正在重新发明***。

您不会通过直接使用 DataReader 填充 DataTable 来获得性能优势。

【讨论】:

【参考方案2】:

如果我不得不猜测,我认为与使用带有 Fill() 方法的 sqldataadapter 相比,使用 sqldatareader 填充数据表不会有任何性能优势。

真正验证该理论的唯一方法是编写自己的实现并进行比较。但是您也可以查看 Fill() 正在执行的代码,以了解它到底在做什么。我建议下载Reflector 来查看代码。

这是我自己做的。这是调用 Fill() 后最终调用的内容:

Protected Overridable Function Fill(ByVal dataTables As DataTable(), ByVal dataReader As IDataReader, ByVal startRecord As Integer, ByVal maxRecords As Integer) As Integer
    Dim num3 As Integer
    Dim ptr As IntPtr
    Bid.ScopeEnter(ptr, "<comm.DataAdapter.Fill|API> %d#, dataTables[], dataReader, startRecord, maxRecords" & ChrW(10), Me.ObjectID)
    Try 
        ADP.CheckArgumentLength(dataTables, "tables")
        If (((dataTables Is Nothing) OrElse (dataTables.Length = 0)) OrElse (dataTables(0) Is Nothing)) Then
            Throw ADP.FillRequires("dataTable")
        End If
        If (dataReader Is Nothing) Then
            Throw ADP.FillRequires("dataReader")
        End If
        If ((1 < dataTables.Length) AndAlso ((startRecord <> 0) OrElse (maxRecords <> 0))) Then
            Throw ADP.NotSupported
        End If
        Dim num2 As Integer = 0
        Dim enforceConstraints As Boolean = False
        Dim dataSet As DataSet = dataTables(0).DataSet
        Try 
            If (Not dataSet Is Nothing) Then
                enforceConstraints = dataSet.EnforceConstraints
                dataSet.EnforceConstraints = False
            End If
            Dim i As Integer
            For i = 0 To dataTables.Length - 1
                If dataReader.IsClosed Then
                    goto Label_00DE
                End If
                Dim container As DataReaderContainer = DataReaderContainer.Create(dataReader, Me.ReturnProviderSpecificTypes)
                If (container.FieldCount > 0) Then
                    If ((0 < i) AndAlso Not Me.FillNextResult(container)) Then
                        goto Label_00DE
                    End If
                    Dim num4 As Integer = Me.FillFromReader(Nothing, dataTables(i), Nothing, container, startRecord, maxRecords, Nothing, Nothing)
                    If (i = 0) Then
                        num2 = num4
                    End If
                End If
            Next i
        Catch exception1 As ConstraintException
            enforceConstraints = False
            Throw
        Finally
            If enforceConstraints Then
                dataSet.EnforceConstraints = True
            End If
        End Try
    Label_00DE:
        num3 = num2
    Finally
        Bid.ScopeLeave((ptr))
    End Try
    Return num3
End Function

您会注意到这随后会调用 FillFromReader():

Friend Function FillFromReader(ByVal dataset As DataSet, ByVal datatable As DataTable, ByVal srcTable As String, ByVal dataReader As DataReaderContainer, ByVal startRecord As Integer, ByVal maxRecords As Integer, ByVal parentChapterColumn As DataColumn, ByVal parentChapterValue As Object) As Integer
    Dim num2 As Integer = 0
    Dim schemaCount As Integer = 0
    Do
        If (0 < dataReader.FieldCount) Then
            Dim mapping As SchemaMapping = Me.FillMapping(dataset, datatable, srcTable, dataReader, schemaCount, parentChapterColumn, parentChapterValue)
            schemaCount += 1
            If (((Not mapping Is Nothing) AndAlso (Not mapping.DataValues Is Nothing)) AndAlso (Not mapping.DataTable Is Nothing)) Then
                mapping.DataTable.BeginLoadData
                Try 
                    If ((1 = schemaCount) AndAlso ((0 < startRecord) OrElse (0 < maxRecords))) Then
                        num2 = Me.FillLoadDataRowChunk(mapping, startRecord, maxRecords)
                    Else
                        Dim num3 As Integer = Me.FillLoadDataRow(mapping)
                        If (1 = schemaCount) Then
                            num2 = num3
                        End If
                    End If
                Finally
                    mapping.DataTable.EndLoadData
                End Try
                If (Not datatable Is Nothing) Then
                    Return num2
                End If
            End If
        End If
    Loop While Me.FillNextResult(dataReader)
    Return num2
End Function

看完这一切后,我可能不得不改变主意。为所有这些编写自己的实现可能确实有可衡量的改进。这些函数中的逻辑比我预期的要多,并且在一遍又一遍地调用 FillNextResult() 时会产生一些函数调用开销。

【讨论】:

感谢您将代码拖出,确实提出了一些问题...但由于它在下面使用数据读取器,因此可能不值得...【参考方案3】:

这里是一个 dataReader 用于一般填充数据表的示例。您可以简单地使用 DataTable 的 Load 方法并将其传递给 DataReader:

DataTable dt= new DataTable();
dt.Load(cmd.ExecuteReader()); //cmd being declared as SqlCommand 

【讨论】:

以上是关于通用 DataReader 代码示例 (.net)的主要内容,如果未能解决你的问题,请参考以下文章

MysqlException 未处理 DataReader 必须关闭此连接 vb.net

asp.net datareader 必须关闭

ADO.NET 四(DataReader)

无法从 .NET OleDB.DataReader 检索行

寻找重置或清除 DataReader 的方法

IBM.Data.DB2.Core DataReader.GetSchemaTable() 方法抛出 NotSupportedException C# .NET 标准