Table of a VFeld from a VCursor

Ed Kleban Ed at Kleban.com
Mon Nov 21 16:21:49 CST 2005




On 11/21/05 3:30 PM, "Ruslan Zasukhin" <sunshine at public.kherson.ua> wrote:

> On 11/21/05 10:34 PM, "Ed Kleban" <Ed at Kleban.com> wrote:
> 
>> In fact, I'll probably publish, or send you to publish, the FieldCursor
>> class hierarchy to use as a V4RB add-on or to include as an example.  It
>> essentially provides the lazy read feature in code until such time as you
>> get around to adding it V4RB.  If I didn't have a way to do this I would be
>> willing to move nearly as much code over to V4RB and feel ok about burning
>> bridges behind myself.  Or I'd have to restructure my use of the database in
>> a far more painful way to manage.
> 
> Can you show small example of usage of V4RB now, and with your classes
> To see difference ?
> 
> 

Sure.

I'm still coding this, nothing is tested, all subject to change.  That said,
here is some code to stare at.  (Actually this was quite a useful exercise;
I found 3 bugs in the process of pasting text here).


// When you define your VTable subclasses you define the FieldCursors
// you want to be able to use in addition to table fields:

Sub CTblForms(db as CRbProjectDB, tableName as String)
  // Initialize the receiver and its fields.
  
  self.name = tableName
   
  // Define the Table Fields
  fFrmFlags = new VByte( "FFrmFlags" )
  fFrmLabel = new VVarChar( "FFrmLabel", 504 )
  fFrmTagTyp = new VVarChar( "FFrmTagTyp", 504)
  fFrmXmlTag = new VVarChar( "FFrmXmlTag", 504)
  
  // Define the FieldCursors
  cursorOnFFrmXmlTag = new CFCVarChar( fFrmXmlTag )
  cursorOnFFrmFlags  = new CFCByte( fFrmFlags )
End Sub


// Subsequently, in your code you can use the FieldCursors
// to randomly access a single field of a given record without
// reading in every single table field when all you need is
// a single field's value:

    flagByteFromRecord32 = MyTblForms.cursorOnFFrmFlags.integerValue( 32 )
    MyTblForms.cursorOnFFrmFlags.integerValue( 21 ) = kFlagValForRec21


// To make this possible...

// You need to define a subclass of CFCField for each different
// kind of Vfield subclass that you want to be able create a
// FieldCursor for.  This gets done once and reused in all the
// applications where you want to use FieldCursors.  It is essentially
// the common FieldCursor add-in code.  Here are some example guts
// out of CFCByte:

Function integerValue(recId as Integer, doUpdateCheck = true) As Integer
  // Return an Integer with the value of the reciever's fcCursorField at
  // recId from the updated fcCursor on fcTable in fcDatabase.
  // If doUpdateCheck is false then assume that no rows have been
  // added to fcTable and that the fcCursor is valid.
  
  if doUpdateCheck and updateFieldCursor then  // fcCursorChanged
    fcFCByte = fcCursor.ByteField( 1 )
  end
  
  fcCursor.position = recId
  return fcFCByte.Value
End Function


Function integerValue(recId as Integer, newIntVal as Integer, _
    doUpdateCheck = true, assigns newValStr as string) As String
 
  // Change the value of the reciever's fcCursorField at recId
  // from the updated fcCursor on fcTable in fcDatabase to newIntVal.
  // If doUpdateCheck is false then assume that no rows have been
  // added to fcTable and that the fcCursor is valid.
  
  if doUpdateCheck and updateFieldCursor then  // fcCursorChanged
    fcFCByte = fcCursor.ByteField( 1 )
  end
  
  fcCursor.position = recId
  fcFCByte.Value = newIntVal
  fcCursor.UpdateRecord
End Function


// The central magic that makes all this work transparently so you
// don't have worry about the state of the FieldCursor is the
// updateFieldCursor method, and the common code called from the
// constructors for all CFCField subclasses:

Protected Function updateFieldCursor() As Boolean
  // Update the receiver's cursor from it's field if necessary.
  // Return true if the Cursor was updated or false if the
  // former fcCursor is fine to use.
  
  const here = "updateFieldCursor"
  
  if fcCursor is nil or fcCursor.RecordCount <> fcTable.RecordCount then
    fcCursor = fcDatabase.SqlSelect( _
        fcSqlString, EVCursorLocation.kClientSide, _
        EVLockType.kNoLocks, EVCursorDirection.kRandom )
    
    #if DebugBuild then
      if fcCursor.RecordCount <> fcTable.RecordCount then
        fail( here, "Update error" )
      end if
    #endif 
 
    return true // Cursor was modified
  else
    return false // Cursor is fine as-is.
  end  
End Function


Sub CFCField(aVField as VField)
  // Initialize the receiver to be a cursor on aVField
  
  const here = "CFCField"
  
  #if DebugBuild then
    if aVField is nil or aVField.Table is nil _
        or aVField.Table.Database is nil then
      fail( here, "Implementation Error" )
    end
  #endif
  
  if not self.checkFieldType( aVField ) then
    fail( here, "Invalid VField subclass" )
  end
  
  // Cache useful values in properties
  fcTable = aVField.Table
  fcSqlString = glue( "Select ", aVField.Name, " from ", fcTable.Name )
  fcDatabase = aVField.Table.Database
  // There is no need or reason to cache the argument aVField.
End Sub


 





More information about the Valentina mailing list