AmosFiveSix.com

Experience, Knowledge, Creativity

  • Increase font size
  • Default font size
  • Decrease font size
Home QueryTree for VB.Net QueryTree.Node.vb

QueryTree.Node.vb

E-mail Print PDF

See my portfolio for information on the Document Builder project that used the Query Tree component.


Imports System.Collections          ' For access to IComparer
Imports System.Data.Common          ' For access to DbCommand, DbDataReader
Imports NACS.Utilities.ObjectReader ' For access to DbObjectReader, Required, Collection
Imports NACS.Helpers.Activator      ' For access to ActivatorHelper
Imports NACS.Helpers.Data           ' For access to DataHelper

Namespace NACS.Data.QueryTree

    Public Class Node

#Region " Member Variables and Properties "

        ' Public fields read from the xml file

        <Required()> _
        Public Name As String = Nothing

        <Required()> _
        Public KeyName As String = Nothing

        <Required()> _
        Public QueryFile As String = Nothing

        <Collection(Type:=GetType(Node))> _
        Public Nodes As Nodes = Nothing

        ' Private member variables corresponding to public properties

        Private m_oRoot As Root = Nothing

        Private m_oParent As Node = Nothing

        Private m_oKeyValue As Object = Nothing

        Private m_iRecordCount As Integer = 0

        Private m_iTotalRecordCount As Integer = 0

        Private m_bIsEntering As Boolean = False

        Private m_bIsLeaving As Boolean = False

        Private m_bIsFirst As Boolean = False

        Private m_bIsLast As Boolean = False

        Private m_oEntity As IEntityInstance = Nothing

        ' Private member variables used internally

        Private m_oCommand As DbCommand = Nothing

        Private m_oDataReader As DbDataReader = Nothing

        Private m_iKeyOrdinal As Integer = -1

        Private m_iParentKeyOrdinal As Integer = -1

        Private m_oObjectReader As ObjectReader = Nothing

        Public Property Root() As Root

            Get

                Return m_oRoot

            End Get

            Private Set(ByVal oRoot As Root)

                m_oRoot = oRoot

            End Set

        End Property

        Public Property Parent() As Node

            Get

                Return m_oParent

            End Get

            Private Set(ByVal oParent As Node)

                m_oParent = oParent

            End Set

        End Property

        Public Property KeyValue() As Object

            Get

                Return m_oKeyValue

            End Get

            Private Set(ByVal oKeyValue As Object)

                m_oKeyValue = oKeyValue

            End Set

        End Property

        Public Property RecordCount() As Integer

            Get

                Return m_iRecordCount

            End Get

            Private Set(ByVal iRecordNumber As Integer)

                m_iRecordCount = iRecordNumber

            End Set

        End Property

        Public Property TotalRecordCount() As Integer

            Get

                Return m_iTotalRecordCount

            End Get

            Private Set(ByVal iTotalRecordNumber As Integer)

                m_iTotalRecordCount = iTotalRecordNumber

            End Set

        End Property

        Public Property IsEntering() As Boolean

            Get

                Return m_bIsEntering

            End Get

            Friend Set(ByVal bIsEntering As Boolean)

                m_bIsEntering = bIsEntering

            End Set

        End Property

        Public Property IsLeaving() As Boolean

            Get

                Return m_bIsLeaving

            End Get

            Friend Set(ByVal bIsLeaving As Boolean)

                m_bIsLeaving = bIsLeaving

            End Set

        End Property

        Public Property IsFirst() As Boolean

            Get

                Return m_bIsFirst

            End Get

            Friend Set(ByVal bIsFirst As Boolean)

                m_bIsFirst = bIsFirst

            End Set

        End Property

        Public Property IsLast() As Boolean

            Get

                Return m_bIsLast

            End Get

            Friend Set(ByVal bIsLast As Boolean)

                m_bIsLast = bIsLast

            End Set

        End Property

        Public Property Entity() As IEntityInstance

            Get

                Return m_oEntity

            End Get

            Private Set(ByVal oInstance As IEntityInstance)

                m_oEntity = oInstance

            End Set

        End Property

        Private Property Command() As DbCommand

            Get

                Return m_oCommand

            End Get

            Set(ByVal oCommand As DbCommand)

                m_oCommand = oCommand

            End Set

        End Property

        Private Property DataReader() As DbDataReader

            Get

                Return m_oDataReader

            End Get

            Set(ByVal oDataReader As DbDataReader)

                m_oDataReader = oDataReader

            End Set

        End Property

        Private Property KeyOrdinal() As Integer

            Get

                Return m_iKeyOrdinal

            End Get

            Set(ByVal iKeyOrdinal As Integer)

                m_iKeyOrdinal = iKeyOrdinal

            End Set

        End Property

        Private Property ParentKeyOrdinal() As Integer

            Get

                Return m_iParentKeyOrdinal

            End Get

            Set(ByVal iParentKeyOrdinal As Integer)

                m_iParentKeyOrdinal = iParentKeyOrdinal

            End Set

        End Property

        Private Property ObjectReader() As ObjectReader

            Get

                Return m_oObjectReader

            End Get

            Set(ByVal oObjectReader As ObjectReader)

                m_oObjectReader = oObjectReader

            End Set

        End Property

#End Region

#Region " Initialize() and Terminate() Methods "

        Friend Sub Initialize(ByVal oRoot As Root, ByVal oParent As Node)

            Me.Root = oRoot

            Me.Parent = oParent

            Me.KeyValue = Nothing

            Me.RecordCount = 0

            Me.TotalRecordCount = 0

            Me.InitInstance()

            Me.InitDataReader()

            Me.InitOrdinals()

            Me.InitObjectReader()

            Me.InitNodes()

        End Sub

        Private Sub InitInstance()

            Try

                Me.Entity = DirectCast(ActivatorHelper.CreateObject(Me.Root.Assembly, Me.Root.Namespace, Me.Name), IEntityInstance)

            Catch oException As Exception

                Throw New NoEntityInstanceException(Me.Root.Assembly, Me.Root.Namespace, Me.Name, oException)

            End Try

        End Sub

        Private Sub InitDataReader()

            Dim sQueryText As String

            Try

                sQueryText = My.Computer.FileSystem.ReadAllText(Me.QueryFile)

            Catch oException As Exception

                Throw New NoQueryFileException(Me.Name, Me.QueryFile, oException)

            End Try

            Try

                m_oCommand = Me.Root.Factory.CreateCommand()

                m_oCommand.Connection = Me.Root.Connection

                m_oCommand.CommandText = sQueryText

                m_oCommand.CommandTimeout = 480

                m_oDataReader = m_oCommand.ExecuteReader()

            Catch oException As Exception

                Throw New NoDataReaderException(Me.Name, Me.Root.ConnectionString, oException)

            End Try

        End Sub

        Private Sub InitOrdinals()

            Try

                m_iKeyOrdinal = m_oDataReader.GetOrdinal(Me.Name & Me.KeyName)

            Catch oException As Exception

                Throw New NoKeyException(Me.Name, Me.KeyName, oException)

            End Try

            If Me.Parent IsNot Nothing Then

                Try

                    m_iParentKeyOrdinal = m_oDataReader.GetOrdinal(Me.Parent.Name & Me.Parent.KeyName)

                Catch oException As Exception

                    Throw New NoParentKeyException(Me.Name, Me.Parent.Name, Me.Parent.KeyName, oException)

                End Try

            End If

        End Sub

        Private Sub InitObjectReader()

            Me.ObjectReader = New DbObjectReader(m_oDataReader)

            Me.AdvanceReader()

        End Sub

        Private Sub InitNodes()

            If Me.Nodes IsNot Nothing Then

                For Each oNode As Node In Me.Nodes

                    oNode.Initialize(Me.Root, Me)

                Next

            End If

        End Sub

        Friend Sub Terminate()

            Me.TermNodes()

            Me.ObjectReader = Nothing

            Me.TermDataReader()

            Me.Entity = Nothing

            Me.KeyValue = Nothing

            Me.Parent = Nothing

            Me.Root = Nothing

        End Sub

        Private Sub TermNodes()

            If Me.Nodes IsNot Nothing Then

                For iNode As Integer = Me.Nodes.Count - 1 To 0 Step -1

                    Me.Nodes(iNode).Terminate()

                Next

            End If

        End Sub

        Private Sub TermDataReader()

            If m_oDataReader IsNot Nothing Then

                m_oDataReader.Close()

                m_oDataReader = Nothing

            End If

            If m_oCommand IsNot Nothing Then

                m_oCommand.Dispose()

                m_oCommand = Nothing

            End If

        End Sub

#End Region

#Region " Process() and Related Methods "

        Friend Sub Process()

            ' When we enter this method, the data reader will be on the current record.

            Me.RecordCount = 0

            Do While IsDataAvailable()

                HandleTransition(Status.DataAvailable)

                Me.AdvanceReader()

            Loop

            HandleTransition(Status.NoDataAvailable)

        End Sub

        Private Function IsDataAvailable() As Boolean

            If Me.ObjectReader.IsDataAvailable Then

                If Me.Parent IsNot Nothing Then

                    Return Me.IsChildInSyncWithParent

                Else

                    Return True

                End If

            Else

                Return False

            End If

        End Function

        Private Function IsChildInSyncWithParent() As Boolean

            ' This compares the current key value of our parent node with the key value for our parent that's in our query data.
            ' If the two don't match, that means we've moved onto a record that doesn't belong to our parent.

            If Me.Root.Comparer.Compare(Me.Parent.KeyValue, DataHelper.GetDataReaderValue(Me.DataReader, Me.ParentKeyOrdinal)) = 0 Then

                Return True

            Else

                Return False

            End If

        End Function

        Private Sub HandleTransition(ByVal eStatus As Status)

            Me.PrepareEntity(eStatus)     ' Loads the new key value and figures if we're leaving and/or entering old/new records.

            If Me.IsLeaving Then Me.Entity.LeaveRecord(Me, Me.Root.Arguments)

            Me.LoadEntity(eStatus)         ' Loads all of the fields in the object from the data source.

            If Me.IsEntering Then Me.Entity.EnterRecord(Me, Me.Root.Arguments)

            ProcessChildren()

        End Sub

        Private Sub PrepareEntity(ByVal eDataStatus As Status)

            Select Case eDataStatus

                Case Status.DataAvailable : SetNewKeyValue(DataHelper.GetDataReaderValue(Me.DataReader, Me.KeyOrdinal))

                Case Status.NoDataAvailable : SetNewKeyValue(Nothing)

            End Select

        End Sub

        Private Sub SetNewKeyValue(ByVal oNewKeyValue As Object)

            ' oNewKeyValue is the new key value we just read from the data source. We need to compare it to the key value for the
            ' previous record (which is in Me.KeyValue at the start of this method) to figure out what kind of transition,
            ' if any, has happened. We then save the new key value into the entity as the current key.

            Dim oPrevKeyValue As Object = Me.KeyValue

            Me.IsEntering = False : Me.IsLeaving = False : Me.IsFirst = False : Me.IsLast = False

            If Me.Root.Comparer.Compare(oPrevKeyValue, oNewKeyValue) <> 0 Then

                ' The new current key is different from the old key, so we know we're transitioning to a new record.

                If oPrevKeyValue IsNot Nothing Then

                    ' The previous key was non-null, so we're leaving a valid record. If the new current
                    ' key is null, then that valid record is the last one.

                    Me.IsLeaving = True

                    If oNewKeyValue Is Nothing Then

                        Me.IsLast = True

                    End If

                End If

                If oNewKeyValue IsNot Nothing Then

                    ' The new current key is non-null, so we're entering a valid record. If the previous
                    ' key is null, then this valid record is the first one.

                    Me.IsEntering = True

                    If oPrevKeyValue Is Nothing Then

                        Me.IsFirst = True

                        Me.RecordCount = 1

                    Else

                        Me.RecordCount += 1

                    End If

                    Me.TotalRecordCount += 1

                End If

            End If

            Me.KeyValue = oNewKeyValue

        End Sub

        Private Sub LoadEntity(ByVal eDataStatus As Status)

            Select Case eDataStatus

                Case Status.DataAvailable : Me.ObjectReader.GetValues(Me.Entity)

                Case Status.NoDataAvailable : Me.ObjectReader.ClearValues(Me.Entity)

            End Select

        End Sub

        Private Sub ProcessChildren()

            If Me.Nodes IsNot Nothing Then

                For Each oNode As Node In Me.Nodes

                    oNode.Process()

                Next

            End If

        End Sub

        Private Sub AdvanceReader()

            Try

                Me.ObjectReader.Read()

            Catch oException As Exception

                Throw New DataReadException(Me.Name, oException)

            End Try

        End Sub

#End Region

    End Class

End Namespace