1

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

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

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

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

4

3 回答 3

3

您找不到DataReader用于一般填充 a的示例的原因DataTable是因为您可以使用 中的Fill()方法做同样的事情DataSet,所以您只是在重新发明轮子。

通过使用 DataReader 直接填充 DataTable,您不会发现性能优势。

于 2009-11-06T01:54:20.907 回答
1

如果我不得不猜测,我认为与使用带有 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() 时会产生一些函数调用开销。

于 2009-11-06T02:01:04.297 回答
0

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

DataTable dt= new DataTable();
dt.Load(cmd.ExecuteReader()); //cmd being declared as SqlCommand 
于 2011-12-09T13:16:48.233 回答