Omnis Technical Note TNDM0001

Using Complex Data Structures

For Omnis Studio version 2.0
By Michael Monschau

How we can use row and list variables to design complex and flexible data structures.

Contents

Introduction
Defining row variables
Using the row variables

Introduction

When designing an Omnis file class we usually think in terms of flat data and at the most complex level may have a list in our file class which contains further rows of data. A typical example is an invoice file class. Here we have some invoice details followed by a list of purchased items.

Simple Invoice

InvoiceNumber
InvoiceDate
InvoiceSubtotal
InvoiceDiscount
InvoiceTotal
InvoiceTax
SalesCode
SalesDepartment
CustomerCode
CustomerName
CustomerAddress
CustomerCity
CustomerStateProvince
CustomerZip
CustomerPhone
CustomerFax
InvoiceItems (list with columns)

  Code
  Description
  Units
  UnitPrice
  Total

With the use of row variables we can structure the data much better.

Tidy Invoice

Invoice (row varible with columns)

  Number
  Date
  Subtotal
  Discount
  Total
  Tax

Sales (row varible with columns)

  Code
  Department

Customer (row varible with columns)

  Code
  Name

FullAddress (row varible with columns)

  Address
  City
  StateProvince
  Zip
  Phone
  Fax

Items (list with columns)

  Code
  Description
  Units
  UnitPrice
  Total

By using row variables the overall appearance is very tidy. Our file class would only contain four fields.

Defining row variables

Row variables are defined in the same way lists are defined. We could have a code class method which defines our file class. We shall call it $defineInvoice. We would call this method every time we need to define our Invoice CRB, i.e. when we insert a new record.

Our $defineInvoice method would call other public methods to define the row variables and lists of the Invoice CRB.

Our first listing is for the method $defineInvoice. This method calls various other methods to define the row variables and list of our ÔfInvoicesÕ file class.

##### Method '$defineInvoice' #####
No. Method text
1 Do method $defineInvoiceDetails (fInvoice.Details)
2 Do method $defineSalesDetails (fInvoice.Sales)
3 Do method $defineCustomerDetails (fInvoice.Customer)
4 Do method $defineInvoiceItems (fInvoice.Items)
   

Next we have the $defineInvoiceDetails method. This method defines the columns for our fInvoice.
Details field passed to the method in parameter one.

 
##### Method '$defineInvoiceDetails' #####
No. Parameter Type Subtype Init.Val/Calc
1 pDetails Field reference  
 
No. Method text
1 Do pDetails.$cols.$add('Number',kInteger,kLongint)
2 Do pDetails.$cols.$add('Date',kDate,kDatetime)
3 Do pDetails.$cols.$add('Subtotal',kNumber,k2dp)
4 Do pDetails.$cols.$add('Discount',kNumber,k2dp)
5 Do pDetails.$cols.$add('Total',kNumber,k2dp)
6 Do pDetails.$cols.$add('Tax',kNumber,k2dp)
   

Next we have the $defineSalesDetails method. This method defines the columns for our fInvoice.
Sales field passed to the method in parameter one.

 
##### Method '$defineSalesDetails' #####
No. Parameter Type Subtype Init.Val/Calc
1 pSales Field reference  
 
No. Method text
1 Do pSales.$cols.$add('Code',kCharacter,kSimplechar,10)
2 Do pSales.$cols.$add('Department',kCharacter,kSimplechar,10)
   

Next we have the $defineCustomerDetails method. This method defines the columns for our fInvoice.Customer field passed to the method in parameter one. Additionally, customer details contains another row variable which we must define. In order to define row variables within row variables, we must first define a local row variable, and then calculate the row variable column 'pCustomer.FullAddress' from our local.

 
##### Method '$defineCustomerDetails' #####
No. Parameter Type Subtype Init.Val/Calc
1 pCustomer Field reference  
 
No. Local Variable Type Subtype Init.Val/Calc
1 FullAddress Row  
 
No. Method text
1 Do pCustomer.$cols.$add('Code',kCharacter,kSimplechar,10)
2 Do pCustomer.$cols.$add('Name',kCharacter,kSimplechar,100)
3 Do pCustomer.$cols.$add(FullAddress)
4 Do method $defineCustomerAddress (FullAddress)
5 Calculate pCustomer.FullAddress as FullAddress
   

Next we have the $defineCustomerAddress method which is called by $defineCustomerDetails.
This method defines the columns for our FullAddress field passed to the method in parameter one.

 
##### Method '$defineCustomerAddress' #####
No. Parameter Type Subtype Init.Val/Calc
1 pAddress Field reference  
 
No. Method text
1 Do pAddress.$cols.$add('Address',kCharacter,kSimplechar,100)
2 Do pAddress.$cols.$add('City',kCharacter,kSimplechar,100)
3 Do pAddress.$cols.$add('StateProvince',kCharacter,kSimplechar,100)
4 Do pAddress.$cols.$add('Zip',kCharacter,kSimplechar,100)
5 Do pAddress.$cols.$add('Phone',kCharacter,kSimplechar,100)
6 Do pAddress.$cols.$add('Fax',kCharacter,kSimplechar,100)
   

Finally we have the $defineInvoiceItems method. This method defines the columns for our fInvoice.Items field passed to the method in parameter one.

 
##### Method '$defineInvoiceItems' #####
No. Parameter Type Subtype Init.Val/Calc
1 pItems Field reference  
 
No. Method text
1 Do pItems.$cols.$add('Code',kInteger,kLongint)
2 Do pItems.$cols.$add('Description',kCharacter,kSimplechar,100)
3 Do pItems.$cols.$add('Units',kInteger,kLongint)
4 Do pItems.$cols.$add('UnitPrice',kNumber,k2dp)
5 Do pItems.$cols.$add('Total',kNumber,k2dp)
   

Implementing complex data structures like this one is a little more work then using a flat structure, but depending on what you are attempting to do, the benefits may outweigh the disadvantages.

Using the row variables

Using the row variables is easy. To refer to a column we simply describe the full path to the column. i.e. 'fInvoice.Customer.FullAddress.City'. We can enter this in calculations, or as the $dataname property of data bound window objects (see example library).

If we have other file classes which contain common blocks of data we may reuse the functions to define row variables within those file classes.

Using row variables also makes it easier to transfer or copy blocks of common data. We can easily calculate one row variable from another or pass a block of data as a single parameter.

Additionally if we ever need to we can add columns to a row variable on a need to need basis without having to do time consuming reorganizations of lots of data. When a row variable in a record is being used we can have a method which simply checks the column count and adds appropriate columns to the row variable. Adding columns does not destroy the data.

 
##### Method '$extendCustomerDetails' #####
No. Parameter Type Subtype Init.Val/Calc
1 pCustomer Field reference  
 
No. Method text
1 If pCustomer.$colcount<4
2    Do pCustomer.$cols.$add('Credit',kNumber,k2dp)
3 End If
   

However, one problem remains. If you want to create indexes of any of the fields stored in a row variable, you can't. One solution is to have a copy of the fields you which to index in the root of the file class. You can still keep the actual fields within the row variable to keep the data block complete. Of course you must remember to keep the copies up to data. The alternative is, any fields you wish to index you do not store in row variables.

Download RTF Document

Download Sample Library