An object oriented data access library for Visual FoxPro
I recently got interested in converting my company’s main Visual Foxpro CRUD application to a Business Object model, rather than old-school free .dbf tables with a bunch of procedural code stuck in all the button clicks and textbox valid() events. I’m sure none of you have ever done such hack-work, but back in the beginning (I started with FPD in 1992, then FPW, then VFP as each was released) that’s how I started. I was a solo developer and had no formal training or access to mentors. It took me a long time to get the vision of how real programming should be done, but I finally learned some of these core fundamentals a few years back, and I’m really enjoying the process of refactoring my app into this BO pattern. I began by reading about the topic in all the usual places, and posted a few questions here and there on several VFP sites (like http://www.foxite.com/ and http://www.universalthread.com/), then I finally hacked out my own basic BO class, after I learned about the SCATTER approach that is widely used to capture data from a table row into an object.
Then, at a pair programming session with a Foxpro developer friend of mine, he showed me Rick Strahl’s West Wind Web Connection for VFP that he’s used for years. Turns out that package has a nice BO class library, called wwBusiness, which is also available as part of a client app tool set from West Wind (called the West Wind Client Tools for VFP http://www.west-wind.com/wwClientTools.asp ). So the Web Connection package and the Client Tools package both have the same wwBusiness BO class library.
Now, the West Wind Client Tools package also has a TON of stuff besides just the BO classes (like SMTP, HTTP, FTP, SQL, XML, JSON, SOAP, blah, blah). You can read all about them at the Client Tools page link I listed above.
One cool thing about the wwBusiness BO class is that it has one single property (nDataMode) to switch between VFP dbf tables and SQL Server, so it’s very helpful if you want to migrate your application’s data to a SQL Server backend and flip the switch once you are ready to move away from dbf tables. And the cool thing is that your app will never know where the data comes from, it just uses the wwBusiness BO to request data, and it comes back as an object that you can work with, then you call the .Save() method on the BO object to write the changes back to the DBF or Sql Server. I tested it, and it actually does work very well.
The wwBusiness.vcx class library has two class types:
- wwBusiness – a single BO class (for fetching a parent record or a single line item)
- wwItemList – a class which will fetch and hold a set of records (like line items on a Sales Order)
Together, these classes can model just about any Parent-Child data set you might have in your app.
I found the two base classes in wwBusiness be good starting points for basic Object Oriented data access, but I have written my own wrappers around them and extended their functionality greatly, and I’ve named my enhanced library “wwBusinessPro”.
You can download wwBusinessPro from the project hosted on BitBucket.org.
The wwBusinessPro library extends the base features of wwBusiness by adding these new features:
- Support for string based lookups
- Support for multiple sets of Child records per each Parent record
- Saving the Parent Primary Key into the Child Foreign Key during the Save() operation
- Adds methods for Ordering and Reordering Child records to control the order the are displayed in
- Table-based Business Object definitions for Parent and Child tables.
Here are the primary two ways I extended the classes:
- The wwBusiness (single BO class) expects an integer PK to do lookups and fetches. I indeed have Integer PKs on my tables, but I sometimes also have a unique lookup string for each parent record, and I wanted the option of using that for fetching a Parent record (and related child records too). So, I created a Get() method which will accept either an Integer or a String. It then calls the native wwBusiness.Load(tnPk) for Integer PK lookups or it will call my extension method LoadByRef(tcLookupString) for string based lookups. The wwBusiness class already had cPKfield out of the box, and I added a cLookupField property to handle string-based lookups. I also enhanced the Save() method to apply the Parent Key to all the Child collection records so that the relational structure required for Parent-Child PK/FK would be automatically handled for me.
- Out of the box, the wwItemList class requires YOU to write a method to fetch the desired child records into a cursor, then it loads that data from your cursor into an array when you call the wwItemList.LoadFromCursor() method. Well, that array would work fine for procedural processing, but for my application I needed to host the child records in a grid, so I needed to service the child records from that local cursor (rather than working on the array items). I wrapped the wwItemList Save() method to get the local records back into the real table from which they came. For my app design, this cursor-based functionality was the biggest missing part from the basic toolkit. I had to write about 3 or 4 methods to handle this workflow in an abstract way so I could have a generic solution for all my child item collections. The main methods I wrote were LoadLineItems() and a wrapper around SaveToCursor() which was needed to handle records that had been deleted from the local working cursor.
You can see a code sample of working with my extended wwBusiness classes here: http://codepaste.net/aascee
Here is a screenshot of the object model that I created with my extended wwBusiniess and wwItemList to create a Job object with several associated child collections: Line Items, Material Items, and Labor Items that are all from child tables related to the Parent record via PK/FK relationship.
Lastly, note that using a BO tool in general not only brings you data handling in an object-based manner with support for various back end data stores, but that same Business Object now becomes *THE* place to put business logic for each of your business objects. Like adding a method for CloseSalesOrder() or AssignJobPriority() or SetDefaultPropertiesForNewJob(), or PrintShippingTicket() etc. With all this properly in place on your Business Objects, creating a UI form becomes a much simpler task of just calling methods on the Business Object. Using this technique, I was able to reduce the code in my CRUD forms by more than 50%!! And now, I have a bunch of cute BOs I can instantiate in code or even right in the command window to work on them without even having a UI screen. Not only that, the same BO can easily support a web-based UI to your same exact data and business logic. It is truly beautiful!
So, as you can see, I did a lot of work on the West Wind classes to prepare them for my app, but two things: 1. It was VERY fun to work all this out, and 2. It works like a charm, and I now have a completely BO-based CRUD app where all the Business logic is nicely tucked away in the BOs and not in my forms or form controls.
Also, FoxPro veteran Kevin Cully is a long-time West Wind user, and he made a presentation on the wwBusiness classes to the Atlanta FoxPro User Group (AFUG) several years ago and prepared a nice 20-page introductory paper here: http://cullytechnologies.com/presentations/wwbusiness/cully_technologies_wwbusiness_presentation.pdf
Man, I wish I had this thing 10+ years ago when as I first began the VFP version of my app. Since I didn’t have a clue what I was doing at the time I started, it wound up a little bit messy, until this came along. I began my own BO efforts around May 2009, and the I abandoned my version in favor of wwBusiness around August 2009.
So go check it out for yourself… You can read the help file online and the package is only $199, and has 10% during August 2009, so about $179 gets you on his customer list and into the surf over at West Wind. You can download a working version with the full source code right from the site. The site also has a reasonably active discussion forum, and Rick is generally very responsive himself.
Note: This post if part of a complete series on the West Wind wwBusiness library. Click here to see the full index.