ComponentOne DataObjects for .NET
Structured Data Storage: Tables and Table Views
DataObjects for .NET (Enterprise Edition) > Schema Objects > Simple Tables > Structured Data Storage: Tables and Table Views

One of the main advantages of DataObjects for .NET over other data frameworks is its ability to represent structured data. For example, suppose we have tables Customers, Orders and Employees (as in the standard Northwind MS Access sample database), and we have defined a composite table CustOrders (see Tutorial 1: Creating a Data Schema) that combines all three tables in a single table according to the following diagram:


Customers Orders Employees

(The Orders – Employees many-to-one relation is defined by the join condition Orders.EmployeeID = Employees.EmployeeID, where EmployeeID is the primary key of the Employees table.)

Suppose the user navigates to a CustOrders row (containing fields from all three tables), and changes the value of Orders.EmployeeID. Then DataObjects for .NET, knowing the structure behind the composite table, changes the employee name (fields Employees.FirstName and Employees.LastName) and other employee attributes according to the changed EmployeeID value.

Or the user can change the value of Employees.FirstName or another Employees field in the simple Employees table. In this case we expect that all CustOrders rows including this Employees rows will show the modified value in the corresponding field.

Or let's take another example: two table views (TableView) showing the data of a single table (in different order, with different filter conditions, different fields, and so on). Here also, once a table row is modified in one table view, the corresponding row will be automatically changed in another.

In other words, DataObjects for .NET always maintains and enforces the structure, relations between tables, composite tables and table views, exactly as you need it to be maintained. What mechanism is responsible for this, how DataObjects for .NET does this? The answer to this question lies in the way DataObjects for .NET stores data. DataObjects for .NET storage is organized according to the structure and role of schema objects, enabling DataObjects for .NET to maintain the correct structure at all times.

The data is stored on the simple table level (except unbound fields). Each table has its own cache, rowset. Table views do not store actual data, instead they store pointers to table rows. In the same way, composite table rows do not store actual data, they also store pointers to simple table rows. This storage structure serves a dual purpose: to eliminate data redundancy and thus conserve memory, and to ensure that the structure is preserved when the user modifies data. Composite table rows and table view rows pointing to the same simple table row share the same data, since the actual data is stored in one place, in a simple table row. When the shared data is modified through one of the composite table rows or through one of the table view rows, all other rows pointing to the same simple table row are notified of the change and display the modified data.

DataObjects for .NET storage is illustrated in the following figure showing how it stores the simple table rows of tables Customers, Orders, Details, and the rows of the CustOrders composite table:



In this figure, you can see that pointers to simple table rows exist only for two tables: Customers and Orders, there are no pointers to Employee rows. This is because the Employees table is connected to its parent in the CustOrders diagram, the Orders table, with a many-to-one relation. In this case, the Employees row is uniquely defined by the Orders row, therefore we do not need a separate pointer for it.

Now you can see how DataObjects for .NET ensures that the correct data structure is maintained at all times regardless of where, in which table view, a modification is made: Any data modification made in a table view ends up in a simple table row. If the table view represents a simple table, this row is found using the single pointer that this table view row contains. For more information, see Table Views. If the table view represents a composite table, the table view uses one of its pointers to simple table rows associated with one-to-many relations, and, if necessary, foreign key values, such as Orders.EmployeeID in the above example, to resolve many-to-one relations. Once the simple table row is found, it is modified. Then DataObjects for .NET notifies all table views (both simple and composite), whose rows point to the modified row, that the row has changed. When, in response to this notification, a client requests the values of those table view rows, they return the changed value, because they always return the current value of the simple table row, using their row pointers.

There is one exception to this storage scheme: unbound fields (also known as calculated) in a table view. These are table view fields that do not correspond to any table field, they were specifically added to the table view by the developer. For more information, see Table View Fields. A table view can have unbound fields, and a composite table can have unbound fields of its own. Unbound composite table fields are those that do not correspond to any field of constituent simple tables, they were added to the composite table by the developer. For more information, see Composite Table Fields. Unbound field values do not belong to simple tables, so they cannot be stored in simple table rows. DataObjects for .NET stores unbound field values in table view rows where they are defined.