如何使用相同的代码从 DataRow 或 DataReader 中读取数据?

Posted

技术标签:

【中文标题】如何使用相同的代码从 DataRow 或 DataReader 中读取数据?【英文标题】:How can I read from a DataRow or a DataReader using the same code? 【发布时间】:2011-10-05 19:53:56 【问题描述】:

目前,我正在使用一个加载了简单数据库“选择”查询的SqlDataReader。每行代表一个域对象,所以我像这样膨胀每个对象:

Dim loadedItems As New List(Of Item)
Dim dr As SqlDataReader = GetItemsDataReader()
While dr.Read()
  Dim item As Item = GetItemFromData(dr)
  loadedItems.Add(item)
End While

我写的GetItemFromData 方法看起来像这样:

Private Function GetItemFromData(dr As SqlDataReader) As Item
  Dim loadedItem As New Item()
  loadedItem.ID = dr("ID")
  loadedItem.Name = dr("Name")
  'etc., etc.'
  Return loadedItem
End Function

在某些情况下,我必须从DataRow 而不是SqlDataReader 读取数据。但代码将完全相同!当我查看我的GetItemFromData 方法时,我想在dr 参数中接受更通用的对象类型,这样我就可以将DataReaderDataRow 一样对待,因为我将编写确切的如果我编写了一个打算使用DataRow 的方法,那么方法中的相同代码。有没有办法做到这一点?

【问题讨论】:

【参考方案1】:

我能想到的唯一方法是包装一些类并实现一个接口 - 类似于:

Interface IIndexer
    Default ReadOnly Property Item(ByVal index As String)
End Interface

Class DataReaderWrapper
    Implements IIndexer

    Private ReadOnly _reader As IDataReader

    Public Sub New(reader As IDataReader)
        _reader = reader
    End Sub

    Public ReadOnly Property Item(index As String) As Object Implements IIndexer.Item
        Get
            Return _reader(index)
        End Get
    End Property
End Class

Class DataRowWrapper
    Implements IIndexer

    Private ReadOnly _row As DataRow

    Public Sub New(row As DataRow)
        _row = row
    End Sub

    Public ReadOnly Property Item(index As String) As Object Implements IIndexer.Item
        Get
            Return _row(index)
        End Get
    End Property
End Class

然后,您必须先包装您的行或阅读器,然后再将其传递给您的方法:

Private Function GetItemFromData(indexer As IIndexer) As Item
    Dim loadedItem As New Item()
    loadedItem.ID = indexer("ID")
    loadedItem.Name = indexer("Name")
    'etc., etc.'
    Return loadedItem
End Function

Dim i As Item = GetItemFromData(New DataRowWrapper(dr))

【讨论】:

这本质上是包装两个对象的适配器模式。我会注意到SqlDataReader 实现了IDataReader,它公开了Item 属性。不幸的是,DataRow 没有实现相同的接口,尽管它公开了相同的功能。在这种情况下,使用适配器模式适应DataRow (class DataRowAdapter : IDataReader),然后让方法接受IDataReader 可能是一种可行的做法。 DataRow 没有实现 IDataRecord 是 bcl 中的一个可悲的错误:( @AnthonyPegram 有道理,但是 IDataReader 中有大量的属性和方法,所以除了实现的一个属性之外,你必须有一堆 NotImplementedException 或类似的属性(或实际实现它们,如果您只关心索引器,这似乎不合适)。 @Joe - 你只能在 IDataRecord 上构建你的包装器,它几乎没有太多的实现。 @AnthonyPegram @JoelCoehoorn 同意 - DataRow 绝对应该实现 IDataRecord。我想知道是否有任何原因,或者这只是一个尚未修复的疏忽。【参考方案2】:

改用DataTable 怎么样:

Dim DataTable table AS new DataTable()
table.Load(GetItemsDataReader())
foreach (DataRow row in table.Rows) 
   Dim item As Item = GetItemFromData(row)
   loadedItems.Add(item)

将您的 GetItemFromData() 方法更改为采用 DataRow 而不是 DataReader(对于 VB.NET/C# 混合伪代码感到抱歉)。

【讨论】:

这可能行得通,但我觉得这是朝着错误方向迈出的一步。

以上是关于如何使用相同的代码从 DataRow 或 DataReader 中读取数据?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 DataGridView 中的一行获取 DataRow

Powershell 连接变量导致 System.Data.DataRow

c#关于DataRow的用法

xml 示例System.Data.DataRow对象

如何使用PowerShell将选择查询的输出从DataSet复制到日志文件?

DataRow数组如何获得行数