AVR for .NET's memory file is an RPG programming interface over .NET's System.Data.DataSet. Under the covers, what really lurks in a memory file is .NET's System.Data.DataSet. The memory file surfaces this DataSet with its dataset property. The DataSet is the central nervous system of the memory file. To understand the memory file you need to understand the DataSet. When you write to and read from a memory file, the memory file's DataSet property is where all that writing and reading is really taking place.

A DataSet is an in-memory cache of data retrieved from a data source. The DataSet is a parent object that consists of one more DataTable objects. For most purposes, especially when using a memory file, you'll only have one table per dataset. Each DataTable object consists of DataColumn and DataRow objects.

Figure 1. The DataSet and its inner members.

The memory file

AVR's memory file is an in-memory file generally used as a temporary data store. Rows are "written" (in quotations because rows are written to memory, not disk) to memory files, usually to later be bound to a .NET user interface element.

Beware that a memory file stores its contents in memory, never on disk. Be mindful of how many rows you write to a memory file. While it is surprising how many rows .NET can sustain in memory, don't get carried away. Not only would lots of rows tax memory, but they would also offer a larger payload across the network. No user wants to to wait on 5,000 rows being rendered in the browser!

Let's take a look at two ways to declare a memory file:

Create a memory file that duplicates all of the fields in a given file:

DclMemoryFile MemFile +
    DBDesc("*Public/DG Net Local") +
    FileDesc("Examples/CMastNewL1") +
    RnmFmt(MemFileR)

The memory file above contains all of the columns in the Examples/CMastNewL1 file. Memory files are using used along with a corresponding DclDiskFile of the same data file, so it's usually necessary to rename the memory file's format.

Create a program-described memory file:

DclMemoryFile MemFile ImpOpen(*Yes) 
    DclRecordFormat Customers 
    DclRecordFld    Customer_CMCustNo  Type(*Packed) Len(9,0)
    DclRecordFld    Customer_CMName    Type(*Char) Len(40)      

The memory file above creates a memory file with two fields. Program-described memory files are useful when you don't need every column in a file. A program-described memory file's format name is explicitly provided with the required DclRecordFormat operation code.

The discussion applies to either way of defining a memory file.

Populating a memory file

The code below writes up to 16 rows to a memory file, after each read of a record from the Customer file.

DclDB DGDB DBName("*Public/DG Net Local") 
            
DclDiskFile Customer +
        Type(*Input) + 
        Org(*Indexed) + 
        Prefix(Customer_) + 
        File("examples/cmastnewl2") +
        DB(DGDB) +
        ImpOpen(*No)  

DclMemoryFile MemFile ImpOpen(*Yes) 
    DclRecordFormat Customers 
    DclRecordFld    Customer_CMCustNo  Type(*Packed) Len(9,0)
    DclRecordFld    Customer_CMName    Type(*Char) Len(40)     

...

Do FromVal(1) ToVal(16)
    Read Customer 
    If Customer.IsEof()            
        Leave
    EndIf

    Write MemFile      
EndDo                   

The result of the code above is that the DataSet property's DataTable property is populated with the rows read from the Customer file. Direct access to the memory file's DataSet is available with this code:

DclFld ds Type(System.Data.DataSet)
ds = MemFile.DataSet

Recall that the DataSet can have more than one DataTable (although used with AVR it rarely, if ever, does). These DataTables are available through the DataSet's Tables collection. The code below fetches the zeroth (the only) DataTable in the DataSet.

DclFld dt Type(System.Data.DataTable)
dt = MemFile.DataSet.Tables[0]

DataColumns and DataRows

Each DataTable comprises a collection of DataColumn objects. These DataColumns define the file's layout (i.e., its field names, their types, and their values). The contents of each DataTable are stored in a collection of DataRows.

First, get the table reference. With it, you're ready to work with the table's rows and columns:

dt = MemFile.DataSet.Tables[0]

Iterate the DataTable's DataColumns with:

ForEach Col Type(DataColumn) Collection(dt.Columns) 
    // Col now contains a reference to a column in the table
EndFor

Iterate the DataTable's DataRows with:

ForEach Row Type(DataRow) Collection(dt.Rows) 
    // Row contains a reference to a row in the table
EndFor 

Putting all that together, the code be;pw loads 16 rows into the memory file and then shows each field value in each DataRow, fetching the values out by field name:

DclDB DGDB DBName("*Public/DG Net Local") 
        
DclDiskFile Customer +
        Type(*Input) + 
        Org(*Indexed) + 
        File("examples/cmastnewl2") +
        DB(DGDB) +
        ImpOpen(*No)  

DclMemoryFile MemFile +
    DBDesc("*Public/DG Net Local") +
    FileDesc("Examples/CMastNewL1") +
    RnmFmt(MemFileR)

BegSr Run Access(*Public) 
    DclFld FieldNameList Type(StringCollection) 

    Connect DGDB 
    Open Customer 

    WriteRowsToMemoryFile()
    FieldNameList = GetFieldNameList()
    ShowFieldValues(FieldNameList) 

    Close *All
    Disconnect DGDB 
EndSr

BegSr WriteRowsToMemoryFile
    Do FromVal(1) ToVal(16)
        Read Customer 
        If Customer.IsEof()            
            Leave
        EndIf

        Write MemFile      
    EndDo 
EndSr 

BegFunc GetFieldNameList Type(StringCollection) 
    DclFld dt Type(DataTable) 
    DclFld FieldNameList Type(StringCollection) New()

    dt = MemFile.DataSet.Tables[0]

    // Iterate each column adding its field name to the collection.
    ForEach Col Type(DataColumn) Collection(dt.Columns) 
        FieldNameList.Add(col.ColumnName.ToString()) 
    EndFor        
    LeaveSr FieldNameList 
EndFunc 

BegSr ShowFieldValues
    DclSrParm FieldNameList Type(StringCollection) 

    DclFld dt Type(DataTable) 

    dt = MemFile.DataSet.Tables[0]

    // Iterate each data row. 
    ForEach dr Type(DataRow) Collection(dt.Rows) 
        // Show the value for each field in the row.
        ForEach FieldName Type(*String) Collection(FieldNameList)
            Console.WriteLine(dr[FieldName].ToString())  
            // Note that field values are also assignable. 
            // Assuming 'FieldName is a string type, you could do this.
            // dr[FieldName] = 'xyz'
        EndFor 
    EndFor 
EndSr 

Summary

While the DataSet is looked down on by purists, there is a lot AVR can do with it. Spend some time seeing what it can do for you.