Using DatasetModel classes to simplify data access from custom code

The Model classes provide an easy way to access and modify data in a consistent way from the client and the server. Model classes are based on  BusinessEntities and can be generated from the BusinessEntityDesigner the Consultingwerk.BusinessEntityDesigner.Plugins.ModelClassGeneratorPlugin plugin. The plugin will generate one DatasetModel for the BusinessEntity and one TableModel for each Temp Table of the ProDataset. The access to the data is provided through an easy to use API which can be used in the same way on the client and on the AppServer. In the following you will see how you can access customer data from a BusinessEntity using the Model classes. As an example we created based on the sports2000 database a CustomerBusinessEntity with two Temp Tables, Customer and Salesrep using the BusinessEntity Designer. Once activated the plugin will generate a series of class files generated in addition to the normal BusinessEntity files every time the BusinessEntity Designer generates code:


CustomerDatasetModel_Generated 

Auto Generated portion of the CustomerDatasetModel class 

CustomerDatasetModel 

DatasetModel of the CustomerBusinessEntity 

CustomerTableModel_Generated 

Auto Generated portion of the CustomerTableModel class 

CustomerTableModel 

TableModel of the Customer Temp Table 

CustomerTableModelFilter 

Filter class for the CustomerTableModel 

SalesrepTableModel_Generated 

Auto Generated portion of the SalesrepTableModel class 

SalesrepTableModel 

TableModel of the Salesrep Temp Table 

SalesrepTableModelFilter 

Filter class for the SalesrepTableModel 

  

The foundation for the functionality of the Model classes is implemented in the base classes located in the Consultingwerk.OERA package: 


Model base class for a Dataset 

Performs the backend requests of the Dataset Model class 

Abstract base class for Temp Table Models 

  

Sample use case 1 

When creating a new order for a customer you might need to display the correct prices for all items without having to save the changes. To make this possible we need to calculate the value based on the item price and the general discount of the customer. Problem here is that we do not have the information about the current customers discount available on the client. Using the Model classes you have an easy way to get that detail without having to deal with the configuration of UI components like the SmartBusinessEntityAdapter or creating your own FetchDataRequest and use the ServiceAdapter to communicate with the backend to get the information and then get the information from a Temp Table. 

See below how to get the customer discount for customer number 10:

DEFINE VARIABLE oCustomerDatasetModel AS Test.ModelClasses.CustomerDatasetModel NO-UNDO. 

oCustomerDatasetModel = NEW Test.ModelClasses.CustomerDatasetModel (10). 

IF oCustomerDatasetModel:Customer:Available THEN  
    MESSAGE oCustomerDatasetModel:Customer:Discount 
        VIEW-AS ALERT-BOX. 

Sample use case 2 

On the backend side you often have to calculate values based on information from tables which are not available within the same BusinessEntity at that time. Now within the DataAccess class you are doing the calculation in, you could implement a query to lookup these values directly from the database or you could use the reliable (central) way of getting the value from another BusinessEntity which makes the solution a lot more future proof and secure. The good point is that you can use the same code from the previous sample to get the discount of customer number 10. 

  

Filtering data  

The definition of filters is pretty easy. Each of the TableModel instances has a property called “Filter” that references a specialized filter class for the table. These filter classes provide an individual property per field that allows you to define queries in a describing manner. 

The provided filter classes are located in the Consultingwerk.OERA.ModelFilter  package: 


Abstracts the access from the ModelFilter classes to the  

TableModel for invoking the Filter 

Abstract base class for generated TableModelFilter classes 

Provides Filter methods for CHARACTER Buffer Fields 

Provides Filter methods for DATE Buffer Fields 

Provides Filter methods for DATETIME Buffer Fields 

Provides Filter methods for DATETIME-TZ Buffer Fields 

Provides Filter methods for DECIMAL Buffer Fields 

Provides Filter methods for INT64 Buffer Fields 

Provides Filter methods for INTEGER Buffer Fields 

Provides Filter methods for LOGICAL Buffer Fields 

You will find all different kinds of operators for filters existing in the filter classes such as EQ, GE, LE, BEGINS and also some more advanced like IsNotUnknownValue. The available operators depend on the data type of the underlying field. 

A sample for a basic filter is to get all customer records between CustNum 2 and 5. 

DEFINE VARIABLE oCustomerDatasetModel AS Test.ModelClasses.CustomerDatasetModel NO-UNDO.   

oCustomerDatasetModel = NEW Test.ModelClasses.CustomerDatasetModel (). 

oCustomerDatasetModel:Customer:Filter:CustNum:GE (2). 
oCustomerDatasetModel:Customer:Filter:CustNum:LE (5). 

oCustomerDatasetModel:Customer:Fill(). 


Another sample for filtering is to get a list of all german customers whose name begins with “L”. 

DEFINE VARIABLE oCustomerDatasetModel AS Test.ModelClasses.CustomerDatasetModel NO-UNDO. 

oCustomerDatasetModel = NEW Test.ModelClasses.CustomerDatasetModel (). 

oCustomerDatasetModel:Customer:Filter:Country:EQ ("Germany"). 
oCustomerDatasetModel:Customer:Filter:Name:Begins ("L"). 

oCustomerDatasetModel:Customer:Fill(). 


Search using the Primary-Key
As you have seen in the very first sample you can retrieve the record for customer number 10 by providing the customer number as a parameter to the CustomerDatasetModel constructor.

oCustomerDatasetModel = NEW Test.ModelClasses.CustomerDatasetModel (10). 


Inside the constructor of the CustomerDatasetModel a filter gets defined for “CustNum equals 10” and executed “Run ()”.

THIS-OBJECT:Customer:Filter:CustNum:EQ (pCustNum). 

THIS-OBJECT:Customer:Filter:Run ().

These alternative constructors are generated by the plugin for every index that has the “default search code generation” flag turned on. This is the default for all unique indexes. You may need to pay attention to the indexes that are used for the default search code generation, as every constructor signature (combination of parameter data types) can only be used once. 


Using the Resultset and accessing Values 

After performing the Run () statement on a filter or calling the Fill method of the DatasetModel the Temp Table of the ProDataset will be populated (by calling into the ServiceAdapter or ServiceInterface). And you can access the values by using the properties of the TableModel instance. Like shown before you can display the Discount value by using the following statement:

MESSAGE oCustomerDatasetModel:Customer:Discount 
    VIEW-AS ALERT-BOX. 

  

Before accessing data you should always check if data is available using the Available property of the TableModel instance and move to the next record you can use the GetNext () method. The following sample demonstrates retrieving a set of records and iterating though the result set. 

DEFINE VARIABLE oCustomerDatasetModel AS Test.ModelClasses.CustomerDatasetModel NO-UNDO. 

oCustomerDatasetModel = NEW Test.ModelClasses.CustomerDatasetModel (). 


oCustomerDatasetModel:Customer:Filter:CustNum:GE (2). 
oCustomerDatasetModel:Customer:Filter:CustNum:LE (5). 

oCustomerDatasetModel:Customer:Fill(). 

DO WHILE oCustomerDatasetModel:Customer:Available: 
    MESSAGE oCustomerDatasetModel:Customer:CustNum SKIP
            oCustomerDatasetModel:Customer:Name 
        VIEW-AS ALERT-BOX. 

    oCustomerDatasetModel:Customer:GetNext ().
END.

  

Updating Data 

The Model classes can also help you when updating data on the frontend or backend. You just need to turn on the TrackingChanges property on the DatasetModel (TrackingChanges = TRUE), then modify whatever fields you need to change and call the SaveChanges method of the DatasetModel. The validation located in the BusinessEntity or DataAccess class will be executed. Validation errors would be thrown by the SaveChanges method and need to be handled by your code. 

In this short sample we increase the discount for Customer number 10 by 5 percent, each time we run this code.

DEFINE VARIABLE oCustomerDatasetModel AS Test.ModelClasses.CustomerDatasetModel NO-UNDO. 

oCustomerDatasetModel = NEW Test.ModelClasses.CustomerDatasetModel (10). 

oCustomerDatasetModel:TrackingChanges = TRUE. 

oCustomerDatasetModel:Customer:Discount = oCustomerDatasetModel:Customer:Discount + 5. 

oCustomerDatasetModel:SaveChanges().


If you want to learn more about how to use Views together with Model classe click here.