TemplateDataReader.vb

Imports System
Imports System.Data
Imports System.Globalization

Namespace DotNetDataProviderTemplate

  Public Class TemplateDataReader
    Implements IDataReader
    Implements IDataRecord

    ' The DataReader should always be open when returned to the user.
    Private m_fOpen As Boolean = True

    ' Keep track of the results and position
    ' within that resultset (starts prior to first record).
    Private m_resultset As SampleDb.SampleDbResultSet
    Private Shared m_STARTPOS As Integer  = -1
    Private m_nPos As Integer    = m_STARTPOS

    '* 
    '* Keep track of the connection to implement the
    '* CommandBehavior.CloseConnection flag. Nothing (a null reference) means
    '* normal behavior (do not automatically close).
    '*
    Private m_connection As TemplateConnection = Nothing

    '*
    '* Because the user should not be able to directly create a 
    '* DataReader object, the constructor is
    '* marked as internal.
    '*

    Friend Sub New(ByRef resultset As SampleDb.SampleDbResultSet)
      MyBase.New
      m_resultset = resultset
    End Sub

    Friend Sub New(ByRef resultset As SampleDb.SampleDbResultSet, ByRef connection As TemplateConnection)
      MyBase.New
      m_resultset = resultset
      m_connection = connection
    End Sub

    '****
    '* METHODS / PROPERTIES FROM IDataReader.
    '****
    Public ReadOnly Property Depth As Integer Implements IDataReader.Depth 
      '*
      '* Always return a value of zero if nesting is not supported.
      '*
      Get
        Return 0
      End Get
    End Property

    Public ReadOnly Property IsClosed As Boolean Implements IDataReader.IsClosed
      '*
      '* Keep track of the reader state - some methods should be
      '* disallowed if the reader is closed.
      '*
      Get
        Return Not m_fOpen
      End Get
    End Property

    Public ReadOnly Property RecordsAffected As Integer Implements IDataReader.RecordsAffected 
      '*
      '* RecordsAffected is only applicable to batch statements
      '* that include inserts/updates/deletes. The sample always
      '* returns -1.
      '*
      Get
         Return -1
      End Get
    End Property

    Public Sub Close() Implements IDataReader.Close
      '*
      '* Close the reader. The sample only changes the state,
      '* but an actual implementation would also clean up any 
      '* resources used by the operation. For example,
      '* cleaning up any resources waiting for data to be
      '* returned by the server.
      '*
      m_fOpen = false
    End Sub

    Public Function NextResult() As Boolean Implements IDataReader.NextResult
      ' The sample only returns a single resultset. However,
      ' DbDataAdapter expects NextResult to return a value.
      Return False
    End Function


    Public Function Read() As Boolean Implements IDataReader.Read
      ' Return True if it is possible to advance and if you are still positioned
      ' on a valid row. Because the data array in the resultset
      ' is two-dimensional, you must divide by the number of columns.
      m_nPos = m_nPos + 1
      If m_nPos + 1 >= (m_resultset.data.Length / m_resultset.metaData.Length) Then
        Return False
      Else
        Return True
      End If
    End Function

    Public Function GetSchemaTable() As DataTable Implements IDataReader.GetSchemaTable
      '$
      Throw New NotSupportedException()
    End Function

    '****
    '* METHODS / PROPERTIES FROM IDataRecord.
    '****

    Public Overloads ReadOnly Default Property Item(ByVal i As Integer) As Object Implements IDataRecord.Item
      Get
        Return GetValue(i)
      End Get
    End Property

    Public Overloads ReadOnly Default Property Item(ByVal name As String) As Object Implements IDataRecord.Item
      Get
        ' Look up the ordinal and return the value at that position.
        Return Me.GetOrdinal(name)
      End Get
    End Property

    Public ReadOnly Property FieldCount As Integer Implements IDataRecord.FieldCount
      ' Return a count of the number of columns, which in
      ' this case is the size of the column metadata array.
      Get
        Return m_resultset.metaData.Length - 1
      End Get
    End Property

    Public Function GetName(ByVal i As Integer) As String Implements IDataRecord.GetName
      Return m_resultset.metaData(i).name
    End Function

    Public Function GetDataTypeName(ByVal i As Integer) As String Implements IDataRecord.GetDataTypeName
      '*
      '* Usually this would return the name of the type
      '* as used on the back end, for example 'smallint' or 'varchar'.
      '* In this case use the simple name of the .NET Framework type.
      '*
      Return m_resultset.metaData(i).type.Name
    End Function

    Public Function GetFieldType(ByVal i As Integer) As Type Implements IDataRecord.GetFieldType
      ' Return the actual Type class for the data type.
      Return m_resultset.metaData(i).type
    End Function

    Public Function GetValue(ByVal i As Integer) As Object Implements IDataRecord.GetValue
      Return m_resultset.data(m_nPos, i)
    End Function

    Public Function GetValues(values() As Object) As Integer Implements IDataRecord.GetValues
      Dim i As Integer = 0
      Dim j As Integer = 0
      
      Do While i < values.Length AND j < m_resultset.metaData.Length
        values(i) = m_resultset.data(m_nPos, j)

        i += 1
        j += 1
      Loop

      Return i
    End Function

      Return i
    End Function

    Public Function GetOrdinal(ByVal name As String) As Integer  Implements IDataRecord.GetOrdinal
      ' Look for the ordinal of the column with the same name and return it.
      Dim i As Integer
      For i = 0 To m_resultset.metaData.Length - 1
        If 0 = _cultureAwareCompare(name, m_resultset.metaData(i).name) Then Return i
      Next

      ' Throw an exception if the ordinal cannot be found.
      Throw New IndexOutOfRangeException("Could not find the specified column in the results")
    End Function

    Public Function GetBoolean(ByVal i As Integer) As Boolean Implements IDataRecord.GetBoolean
      '*
      '* Force the cast to return the type. InvalidCastException
      '* should be thrown if the data is not already of the correct type.
      '*
      Return CType(m_resultset.data(m_nPos, i), Boolean)
    End Function

    Public Function GetByte(ByVal i As Integer) As Byte Implements IDataRecord.GetByte
      '*
      '* Force the cast to return the type. InvalidCastException
      '* should be thrown if the data is not already of the correct type.
      '*
      Return CType(m_resultset.data(m_nPos, i), Byte)
    End Function

    Public Function GetBytes(ByVal i As Integer, ByVal fieldOffset As Long, buffer() As byte, ByVal bufferOffSet As Integer, ByVal length As Integer) As Long Implements IDataRecord.GetBytes
      ' The sample does not support this method.
      Throw New NotSupportedException("GetBytes not supported.")
    End Function

    Public Function GetChar(ByVal i As Integer) As Char Implements IDataRecord.GetChar
      '*
      '* Force the cast to return the type. InvalidCastException
      '* should be thrown if the data is not already of the correct type.
      '*
      Return CType(m_resultset.data(m_nPos, i), Char)
    End Function

    Public Function GetChars(ByVal i As Integer, ByVal fieldOffSet As Long, buffer() As Char, ByVal bufferOffSet As Integer, ByVal length As Integer) As Long Implements IDataRecord.GetChars
      ' The sample code does not support this method.
      Throw New NotSupportedException("GetChars not supported.")
    End Function

    Public Function GetGuid(ByVal i As Integer) As Guid Implements IDataRecord.GetGuid
      '*
      '* Force the cast to return the type. InvalidCastException
      '* should be thrown if the data is not already of the correct type.
      '*
      Return CType(m_resultset.data(m_nPos, i), Guid)
    End Function

    Public Function GetInt16(ByVal i As Integer) As Int16  Implements IDataRecord.GetInt16
      '*
      '* Force the cast to return the type. InvalidCastException
      '* should be thrown if the data is not already of the correct type.
      '*
      Return CType(m_resultset.data(m_nPos, i), Int16)
    End Function

    Public Function GetInt32(ByVal i As Integer) As Int32 Implements IDataRecord.GetInt32
      '*
      '* Force the cast to return the type. InvalidCastException
      '* should be thrown if the data is not already of the correct type.
      '*
      Return CType(m_resultset.data(m_nPos, i), Int32)
    End Function

    Public Function GetInt64(ByVal i As Integer) As Int64 Implements IDataRecord.GetInt64
      '*
      '* Force the cast to return the type. InvalidCastException
      '* should be thrown if the data is not already of the correct type.
      '*
      Return CType(m_resultset.data(m_nPos, i), Int64)
    End Function

    Public Function GetFloat(ByVal i As Integer) As Single Implements IDataRecord.GetFloat
      '*
      '* Force the cast to return the type. InvalidCastException
      '* should be thrown if the data is not already of the correct type.
      '*
      Return CType(m_resultset.data(m_nPos, i), Single)
    End Function

    Public Function GetDouble(ByVal i As Integer) As Double Implements IDataRecord.GetDouble
      '*
      '* Force the cast to return the type. InvalidCastException
      '* should be thrown if the data is not already of the correct type.
      '*
      Return CType(m_resultset.data(m_nPos, i), Double)
    End Function

    Public Function GetString(ByVal i As Integer) As String Implements IDataRecord.GetString
      '*
      '* Force the cast to return the type. InvalidCastException
      '* should be thrown if the data is not already of the correct type.
      '*
      Return CType(m_resultset.data(m_nPos, i), String)
    End Function

    Public Function GetDecimal(ByVal i As Integer) As Decimal Implements IDataRecord.GetDecimal
      '*
      '* Force the cast to return the type. InvalidCastException
      '* should be thrown if the data is not already of the correct type.
      '*
      Return CType(m_resultset.data(m_nPos, i), Decimal)
    End Function

    Public Function GetDateTime(ByVal i As Integer) As DateTime Implements IDataRecord.GetDateTime
      '*
      '* Force the cast to return the type. InvalidCastException
      '* should be thrown if the data is not already of the correct type.
      '*
      Return CType(m_resultset.data(m_nPos, i), DateTime)
    End Function

    Public Function GetData(ByVal i As Integer) As IDataReader Implements IDataRecord.GetData
      '*
      '* The sample code does not support this method. Normally,
      '* this would be used to expose nested tables and
      '* other hierarchical data.
      '*
      Throw New NotSupportedException("GetData not supported.")
    End Function

    Public Function IsDBNull(ByVal i As Integer) As Boolean Implements IDataRecord.IsDBNull
      Return m_resultset.data(m_nPos, i) Is DBNull.Value
    End Function

    '*
    '* Implementation specific methods.
    '*
    Private Function _cultureAwareCompare(strA As String, strB As String) As Integer
      Return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, CompareOptions.IgnoreKanaType Or CompareOptions.IgnoreWidth Or CompareOptions.IgnoreCase)
    End Function

    Public Sub Dispose() Implements IDisposable.Dispose
      Me.Dispose(True)
      System.GC.SuppressFinalize(Me)
    End Sub

    Public Sub Dispose(disposing As Boolean)
      If disposing Then
          Try
            Me.Close()
          Catch e As Exception
            Throw New SystemException("An exception of type " & e.GetType().ToString() & _
                                      " was encountered while closing the TemplateDataReader.")
          End Try
      End If
    End Sub

  End Class
End Namespace