Getting started with EverClassy Dataset

The purpose of EverClassy Dataset is simple to be stated: to interoperate objects and dataware components! Yet it's a clear and short purpose, such a task hides some particular challenges that justify the long wait until now. For instance, once the dataset is loaded with a collection of instances, to represent them as records is easy (as a matter of fact, not as easy as it looks!), but where are those instances come from? A classic TObjectList? Or its much nicer generic version, TObjectList<T>? They look alike, but they are very different data types! Or maybe a TCollection, another useful class with really particular behavior? Or maybe the programmer has a very good reason to use a completely different, house-build object collection (let's say, a persistent object collection!)?

Besides that, when a new record is inserted in the dataset, it must generate a new instance! How is such an instance created? Must the class have a default constructor? What if the application design requires a more complex instantiation process? What about deleting a record? Is it enough to call Free() on the corresponding instance or something more has to be done?

Well, there is a number of variables in a scenario where an application is built on a truely object oriented design. A dataset up to the challenge of such a scenario must be able to deal with all those little particularities and any experienced programmer knows that the real work is precisely to handle those little particularities!

In the following sections, the main EverClassy Dataset concepts will be presented! The reader must have in mind that the component is the result of specific effort to address the problems stated above and some others, in order to make it powerful, flexible, resourceful and easy to use. All those together provide the programmer a tool capable of giving him/her the much desired and waited ability to map native Delphi objects into dataset records!

The working ground

When EverClassy Dataset is installed in a computer, the setup wizard deploys some sample applications specifically written to exemplify the use of the product's features. This tutorial will focus on one of those samples to explain the concepts around the operation of EverClassy Dataset! It's a Delphi project named People.VCL! There is also a twin project named People.FMX for FireMonkey, but it will not be addressed at this time.

The following image shows the only form existing in this application.

Forms.People.VCL

In such a form, the user is able to see a list of people of interest (the TDBGrid on the left) and the details of the selected one (the several dataware components on the panel on the right). Over the TDBGrid component there is a well known TDBNavigator that allows the user to browse the records, insert or delete a new record and all the other operations this component provides.

On the details panel there is another instance of TDBGrid that lists all the contact methods a given person has. It means that the application has a master-detail relationship between two datasets, a very usual configuration in database applications!

The following sections show how such an application was written all based on EverClasse Dataset!

EverClassy Dataset IDE

The name of the show

EverClassy Dataset is implemented by the Delphi VCL component named TECDataset. It's available inside the Delphi IDE under the component tab named EverClassy. It is the single component present in that tab!

Like any other dataset, it's a non-visual component that should be placed on a form or datamodule e

  • Named (property Name) and configured;
  • Have fields added (property Fields) and configured;
  • Have events handled.

As it can be seen, in design-time terms, it's basically just another dataset component!

EverClassy Dataset IDE

The domain model

EverClassy Dataset targets the idea of placing domain (or business) rules along a set of classes, creating a set of abstractions that represent the actual concepts existing in reality. The portion of the reality that is considered important to be studied is named the application domain and the object oriented model that represents the domain is usually called the domain model. The entire process or method that focus on the domain to develop the application models is nowadays called Domain Driven Design, or simply, DDD!

So, in a DDD project the starting point is, of course, the domain model! The model for the People.VCL application is just the same as People.FMX application and it is presented at the right.

This model is expressed as a UML class diagram and presents some classes and the relationships among them!

As a DDD project, this model is the starting point of all the design. The classes identified after some study on the reality (the domain) should then be implemented in a programming language, Delphi in the case of this tutorial!

Implementing those classes is not a problem at all in this application. The real problem comes when the programmer desires to create a simple form to handle instances of those classes, since the visual components are not able to directly handle objects and properties that do not descend from TPersistent and not registered to the Delphi IDE.

Some kind of intermediary component must be used to bridge the dataware components to class instances. This component is TECDataset!

The GUI design

Using TECDataset to create a fully functional GUI that is able to handle the domain objects is very simple and (almost) nothing different than the practice required by any other dataset. The image below shows the form already completely built, containing all the components configured to work.

Forms.People.VCL

The first thing to notice is the presence of three instances of TECDataset. One is dedicated to handle instances of TPerson (component ECDatasetPeople), which is the root object (as shown by the model above). In this application, everything begins with an instance of TPerson!

The domain model shows that TPerson instances can hold one instance of TAddress. The relationship between TPerson and TAddress is a composition what in code generates a master-detail relationship. That's why there is another TECDataset instance (ECDatasetAddress), dedicated to handle TAddress instances.

The model also shows that an instance of TPerson can also hold an arbitrary number of TContact instances, which happens to be an abstract, never instantiated class. In fact, what really happens is that only the two subclasses of TContact, TPhone and TEMail are indeed instantiated. Once those instances are related to a TPerson instance by an aggregation, another master-details relationship is stablished. As a consequence, a third TECDataset instance (ECDatasetContact) has to exist to hold the TPhone and TEmail instances.

The rest of the form design is the same it would be with any other ordinary dataset. Instances of TDataSource, TDBNavigator, TDBEdit, TDBGrid and so on are used in the very same manner they always are, leveraging all the programmer's knowledge (and probably even code) already existing!

Field mappings

As any other dataset, TECDataset is composed by a number of fields. In usual database bound dataset, those fields correspond directly to columns of a result set, sometimes returned as the result of the execution of a SQL statement. However, the nature of TECDataset is not connected to any database system, but to native Delphi objects. That's why the fields of TECDataset are bound to object properties!

The fields defined in TECDataset map to the properties with the same name. So, everytime a field receives a value, such a value is directly assigned to the property with the same name. If a field does not have a corresponding property, it acts like a buffer, just holding the value.

In order the create master-detail relationships, TECDataset also supports TDatasetField instances, that are assigned to a DatasetField property in other TECDataset, in a configuration very similar to the one found in TClientDataset.

Loading the objects

Once the instance of TECDataset is completely configured and having all the fields defined, it's ready to start to work. What is needed now is to assign a collection of TPerson to ECDatasetPerson and to open the dataset. The other two datasets do not need to be explicitly open, since they are detail datasets. In such a circunstance, the opening of the master dataset generates a chain reaction that ends up with all the dependent datasets also open and ready to work.

Forms.People.VCL.OnShow

The piece of code at the right shows how the dataset is open. The LoadPeople method loads the People list with some instances. The People list is declared as People: TObjectList<TPerson> and does not have any special preparation. It is declared, instantiated and loaded! After that it's just assigned to the TECDataset.Source property and the dataset is open. The call of the method Open commands the dataset to iterate over the collection assigned to the Source property (the People list) to enumerate the items and map them to records.

Here comes a very important aspect of the design and operation of TECDataset. How does the component use the object assigned to the Source property and what kind of object can be assigned to it?

The Source property is declared as TObject what means it accepts every instance desired. It's possible to assign a single instance that will be mapped to a single record in a dataset the will not accept inserts and it's possible to assign a collective object that hold a number of other objects that will actually be mapped to the records instead the collection itself.

How the TECDataset knows how to proceed in any case? The answer is the dataset adapter!

The EverClassy Dataset Adapter

In order to give the maximum flexibility and versatility to the programmer, TECDataset works with a companion object named EverClassy Dataset Adapter. If the instance assigned to the Source property does not have an adapter defined to its class, such an instance is directly operated by TECDataset as a single row dataset that will not accept insert operations. It will be possible to map fields to properties and assign values to those fields. The dataset will work perfectly, but it will be a single row dataset, period!

However, if the instance assigned has an adapter defined to its class, such an adapter will be used by the dataset to find out how many instances are held by it and, when needed, will interact with the adapter to create ou delete instances! The adapter is responsible to bridge the dataset and the object collection!

An adapter is an object that implements the IECDatasetAdapter interface. This object will operate the actual collection everytime the dataset needs to. Different kinds of collective objects have to have different and dedicated implementations of that interface. Those implementations are registered to a class and everytime TECDataset is open it looks for an adapter to the object present in the Source property. If such an adapter exists, it's used to load the records and the dataset works!

Forms.People.VCL.Initialization

The piece of code at the right shows the registration of the three adapters that must exist to support the use of the three domain classes that the People.VCL application works on.

In this particular application, the programmer decided to make use of the class TObjectList<T> and there is a generic implementation of the adapter to such a data type already implemented with EverClasse Dataset. No implementation is needed from the programmer. The adapter is ready to be used and will work with any instance of TObjectList<T>. The registration is enough to get everything working when a dataset bound to such a source of instances is open!

This design delegates to the adapter the responsibility to work with the collection and deal with any particular needs it has, hiding from the dataset itself any specificities. It also enables the use of any kind of object collections. If a programmer has a very special instance collection that his/her application needs to work with, it will also work with TECDataset. The programmer just have to implement an adapter!

Among the samples deployed by the setup wizards, an example of an adapter implementation is provided in order to guide anyone who needs to create a new EverClassy Dataset Adapter.

Conclusions

This tutorial presented a general view of the TECDataset component. Along the text several conceps regarding the EverClasse dataset product were discussed, such as:

  1. TECDataset maps instances to records and properties to fields;
  2. It's possible to declare TDatasetField fields to stablish master-details relationships between datasets;
  3. In order to work with any kind of collective object and access its held instances, TECDataset works with a companion object that implements the IECDatasetAdapter interface;
  4. Any kind of collection can be handled by TECDataset if there is an adapter specialized to deal with it.

The particular design and operation of TECDataset targeted, since the beggining, the versatility of working with all ranges of objects, no matter the class ecosystem they belong to. This particular requirement is considered the master key to enable the component to be part of any kind of application that are based on domain objects.

Inovativa sincerely hopes that by reading this tutorial, the main doubts and questions about EverClassy Dataset are answered. However, if any questions still remain, it may be sent to support@inovativa.com.br. We will be glad to make it clear any doubts you have!