【问题标题】:How can I read from a DataRow or a DataReader using the same code?如何使用相同的代码从 DataRow 或 DataReader 中读取数据?
【发布时间】: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 的方法,那么方法中的相同代码。有没有办法做到这一点?

【问题讨论】:

    标签: .net datareader 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# 混合伪代码感到抱歉)。

    【讨论】:

    • 这可能行得通,但我觉得这是朝着错误方向迈出的一步。
    猜你喜欢
    • 2011-09-11
    • 1970-01-01
    • 2013-09-01
    • 1970-01-01
    • 2014-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多