Lookup Fields

The LookupFields desktop sample demonstrates how to add lookup fields, which derive or "look up" their values from a field in another table's field, to a DADataTable.

Getting Started

The Desktop sample is typically located in /Developer/RemObjects Software/Samples/Data Abstract/Desktop/LookupFields, though you may have installed the Data Abstract for Cocoa and it's samples in another location.

To build it, you will of course need Xcode, and like all the samples provided with Data Abstract for Cocoa you will need to be running the Relativity Server with the DASamples Domain and the Simple Schema available.

Running the Sample

This sample retrieves the records from the "Orders" where their type is "2", it then adds 4 lookup fields which uses values from 4 other tables ("Workers", "Clients", "OrderStatus" and "OrderType") and displays the results in the table.

When this sample is run you will see an empty table and a toolbar which contains a button and a pop-up. The button "Load Orders" will retrieve the required tables and then add the lookup fields before displaying the results in the table. The "Servers" popup contains a list of available servers discovered by the Zeroconf discovery system. When the sample is run, it starts a Zeroconf discovery service that looks for instances of Relativity Server running on the local network. Any discovered servers will be added to the popup, if no servers are discovered then the dropbox on the toolbar will be empty. You can specify a server address yourself by clicking on the popup and then clicking on "Specify custom URL...".

Examining the Code

The code for creating the connection to the server and handling logging in is covered by other samples. In this section we shall focus solely on how you add calculated and lookup fields.

NOTE If the table name, or the field names do not exist then an ROException will be raised and should be handled appropriately.

App Structure

The sample is built around four classes; AppDelegate, DataAccess, ServiceAccess, and RegisterServiceWindowController.

The DataAccess class handles everything related to interacting with the Data Abstract SDK; including retrieving data from an instance of Relativity Server and applying changes back to the server. Here beginGetData retrieves all of the tables required (Providers, Clients, OrderType, Orders and OrderDetails) using the methods getReferences and getOrders, then setupData makes use of those tables to add the calculated and lookup fields; the code below comes from this class.

The ServiceAccess class handles the discovery of any instances of Relativity Server that are available on the local network using ROZeroConf which is a feature available with the Remoting SDK that Data Abstract is built upon. ServiceAccess sets up a ROZeroConfBrowser Class object which searches for any servers that broadcast a value matching the value defined for RELATIVITY_SERVICE_NAME. When a service is found, or indeed disappears, the server list is updated and the popup with the list of available servers is also updated. It also handles the registration of custom server addresses. To explore further the ServiceAccess class and Zeroconf discovery see the article: The ServiceAccess Class and Zeroconf discovery.

The RegisterServiceWindowController class is a subclass of NSWindowController which handles the UI aspects of a user manually adding a server url.

Lastly the AppDelegate class handles the primary setup of the application, registers that it will listen for notifications broadcast by the ServiceAccess and DataAccess classes, and acts as a delegate to the RegisterServiceWindowController, DataAccess and NSTableView classes. The main thing of note is that the dataIsReady method is called when the NOTIFICATION_DATA_READY notification is received, which causes the table to update the table with the newly received data.

Adding a Lookup Field

There are two ways to add a lookup field, the first is by using the addLookupFieldName:sourceField:lookupTable:lookupKeyField:lookupResultField: method of DADataTable, the other way is to manually define a DALookupFieldDefinition object and pass it to the table using the addLookupField: method.

Here the addLookupFieldName:sourceField:lookupTable:lookupKeyField:lookupResultField: method is used, which takes the following arguments:

  • Name a unique name to be given to the lookup field.
  • sourceField the field that will be used as the key value for matching against the lookupKeyField
  • lookupTable takes a reference to the lookup table
  • lookupKeyField the key field in the lookupTable that will be used to match against the sourceField
  • lookupResultField the field in the lookup table that will be used as the result when the sourceField and lookupKeyField match

In the code below there are four lookup fields being added to the "Orders" table. For the first one we are adding a new field with the name "StatusName", whose source field is the Status field of the Orders table, this will act as the key we will use to look up a value. The "OrderStatus" table is assigned as the lookup table and the Id field is field we are going to match against the Status field. If a match is found the value in the Name field of the appropriate row is returned.

//DataAccess.m
- (void)setupData {
  [self.ordersTable addLookupFieldName:@"StatusName"
                           sourceField:[self.ordersTable fieldByName:@"Status"]
                           lookupTable:self.orderStatusTable
                        lookupKeyField:[self.orderStatusTable fieldByName:@"Id"]
                     lookupResultField:[self.orderStatusTable fieldByName:@"Name"]];

  [self.ordersTable addLookupFieldName:@"TypeName"
                           sourceField:[self.ordersTable fieldByName:@"Type"]
                           lookupTable:self.orderTypeTable
                        lookupKeyField:[self.orderTypeTable fieldByName:@"Id"]
                     lookupResultField:[self.orderTypeTable fieldByName:@"Name"]];

  [self.ordersTable addLookupFieldName:@"ManagerName"
                           sourceField:[self.ordersTable fieldByName:@"Manager"]
                           lookupTable:self.workersTable
                        lookupKeyField:[self.workersTable fieldByName:@"WorkerId"]
                     lookupResultField:[self.workersTable fieldByName:@"WorkerName"]];

  [self.ordersTable addLookupFieldName:@"ClientName"
                           sourceField:[self.ordersTable fieldByName:@"Contractor"]
                           lookupTable:self.clientsTable
                        lookupKeyField:[self.clientsTable fieldByName:@"ClientId"]
                     lookupResultField:[self.clientsTable fieldByName:@"ClientName"]];
}