通用 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】:您找不到用于一般填充DataTable
的DataReader
示例的原因是因为您可以使用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
IBM.Data.DB2.Core DataReader.GetSchemaTable() 方法抛出 NotSupportedException C# .NET 标准