Second in a two part series |
by Clayton Jones |
In
the first article in this series we discussed how to run a GUI dialog window in its own
thread, and the importance of ensuring that the program flow exits the routine properly so
that the threads memory is released. In this article we will see how our
ability to do this provides an elegant solution to a sticky problem: data access in event
driven applications. As developers, we are familiar with the techniques for allowing multiuser access to a database. But what happens when an event driven system allows a single user to open the same table several times at once within the same application? It does not work, of course, without some special handling. There are essentially three ways of doing this: a data dialog class of some sort, unique aliases, and threaded dialogs. |
The Data Dialog Class |
There is an
example of a data dialog class in the Xbase++ sample code. It is in
datadlg.prg, located in the "\source\samples\apps\mdidemo\" subdirectory.
An examination of this class reveals an :area instance variable which holds a reference to
the work area, and a rather complex set of notification routines. This class works
well but has several drawbacks. First, this particular design can only handle opening one table. In real world applications it is common to have data entry routines in which several tables are open, often with complex interactions taking place in the underlying business logic. In many cases, therefore, this design will have to be modified. In addition, this data dialog uses the behavior model of being automatically in the edit mode, with the active editable fields predetermined. This is a simple behavior model which works well in certain narrowly defined circumstances or particular design strategies, but is often unsuitable in real world database applications that fit within a broader design. In my experience, it is more often necessary to have the data entry form initially displayed in View mode, with the user initiating the Edit, which in turn offers specific "Save" and "Cancel" options. Furthermore, it is not uncommon to need more than one edit option, each one activating a different subset of fields within the form. In my early years of Clipper work I designed a template which contains all of the view/add/edit/ delete logic commonly needed in a data entry window. It works well, and in many cases is adequate just as it is. I simply plug it in and add the particulars. However, having created many different kinds of applications over the years, I can say from experience that I often have to modify that template. The point here is that there is no common behavior model which can serve unmodified in every situation. Because of the complex interactions of the notification routines which are entertwined with the behavior logic, the sample data dialog does not easily lend itself to modification. If the Xbase++ user is just getting started, perhaps coming from a Clipper background without previous OOP experience, this model can be confusing and difficult to understand. For these reasons, in my opinion, this is not a good choice to use as a foundation for data entry dialog design. Fortunately, Xbase++ offers other solutions. |
The Unique Alias |
In order to
help manage data access in an event driven application, Xbase++ has introduced
the the unique alias. When a table is opened in a work area, Xbase++ assigns a
unique alias for that table. In Clipper, if we open a table like this:
the alias automatically assigned will be the same as the DBF name, "customer". If we wish to use a different alias, it may be specified using the ALIAS command:
In Xbase++ we have the same two options except that a unique alias is assigned, so the same table may be opened more than once at the same time, each instance receiving a different alias. This example shows a table being opened four times:
Therefore, in order to allow a data access routine to be run multiple times at once, all we have to do is assign that unique alias to a variable using the alias() function, and then use that variable with the alias operator for data manipulation:
If such a routine were run several times at once by the user, each instance would have its own unique alias and there would be no conflict. Of course the usual record locking and error handling methods should be employed, as in any multiuser application. It would seem as if we have the perfect solution for the event driven environment. Indeed, this method works extremely well in very simple routines with one or perhaps two tables opened. Consider, however, a more complex routine with five tables open and a temporary table created to hold a batch of data which will be resolved later. If subroutines are called, we must be careful to pass the alias variables to them. We become totally dependant on the variables because we dont know what the actual alias names are. It can quickly become a tangled mess that is confusing and difficult to maintain. Fortunately, in using our threaded dialogs we find an even better solution |
Using Threaded Dialogs |
Along with
the unique alias, Xbase++ gives us the concept of the "work space".
The work space is a "container" for work areas. When we launch a
new thread, as we learned how to do in the previous article, each thread implicitly has
its own work space. Each work space is a completely encapsulated environment which,
for event driven data access purposes, functions like a separate application. If
data access routines are run in their own threads, we can dispense with the burden of
multiple unique alias variables and write code in the manner to which we are accustomed:
I have not found any problems using this method so far in my testing. During one experiment I had sixteen instances of a small data entry dialog open at once. I was able to switch among them at will, editing different records in the table, leaving edits active while switching to others, coming back later to save or cancel them, all without any problems. They performed as if they were sixteen different applications. If a subroutine is called from a threaded routine, the subroutine will be executing its code within the same thread, and will be encapsulated and protected by it. We thus have what seems like an ideal method. |
Conclusion |
In my own
work with Xbase++ to date, I have found the threaded dialog to be the easiest
and least cumbersome way to ensure problem free data access in an event driven
application. The unique alias method also has its merits, and I use that in simple
"black box" type routines of which, because of their very nature, we have no
foreknowlege of how they will be used. It is possible that they may not be called in
a separate thread, and so must have their own protection built in. Using the LaunchPad() routine described in the previous article, it becomes a relatively easy matter to create a main application window and menu running in the primary thread, and have most routines launched from the main menu executing in their own threads. By keeping the data access solution separate from the data dialog behavior logic, we are free to design a behavior model without that extra burden, one which is more easily modified to suit particular needs. |
Copyright © 1999-2006 Clayton Jones |
Return to: Articles Page |Top-Down Page | Software And Services | Home