Browse DevX
Sign up for e-mail newsletters from DevX


Introducing the CursorAdapter Class : Page 8

One of the most exciting new features of Visual FoxPro 8 is the CursorAdapter class, which provides a common interface for working with data from many different sources. Chuck takes you with him on an adventure in exploring how to use CursorAdapter to change the way you relate to data in VFP 8, whether native tables, ODBC, OLE DB, or XML.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Updating XML Data
The next step is to determine how to make this cursor updatable so that the changes can be posted back to our SQLXML server. SQLXML can take a special XML document, known as an UpdateGram, and use it to post changes to the database directly. In VFP7, this document could be created by calling the XMLUpdateGram function. With VFP 8 and the CursorAdapter, this is automatically built in with the UpdateGram property.

The first step is to set up the updatable properties and establish an Update command. Set up the properties at the top of the class definition and provide the method call for the Update command by adding a line of code to the Init method of the CursorAdapter.

   KeyFieldList = 'customerid'
   Tables = 'customers'
   UpdatableFieldList = ;
     "companyname, contactname, contacttitle, "+;
     "address, city, country " 
   UpdateNameList= ;
     "customerid customers.customerid, " + ;
     "companyname customers.companyname, " + ;
     "contactname customers.contactname, " + ;
     "contacttitle customers.contacttitle, " + ;
     "address customers.address, " + ;
     "city customers.city, country customers.country"  
   FUNCTION INIT() as Boolean 
     LOCAL llRetVal, lcMsg, laErr[1]
     this.UpdateCmd = "this.UpdateXML()"
     this.SelectCmd = "this.GetXML()"
     ** balance of code skipped...
Note that we could have placed the property settings for UpdateCmd and SelectCmd in the list of properties that precede the Init method—it works the same either way. Regardless, the first part of this code should be familiar by now, where we set the KeyFieldList, Tables, UpdatableFieldList and UpdateNameList properties. Without these property settings, no UpdateGram can be created.

After that, we establish the UpdateXML method as the CursorAdapter's UpdateCmd. There are no parameters passed to the UpdateXML method, however, so all the work of determining the changes must be handled within this method. Also, since an XML-type CursorAdapter has no default update mechanism, you must write the code to post the changes to the XML data source. This is all done in the code for UpdateXML (and oXMLDOM_Access), shown in Listing 5.

In this code, we use the XMLHTTP object to post the changes to the server. This is done by loading the contents of the UpdateGram property into an XMLDOM (instantiated by the included Access method) with the LoadXML method, opening a connection to the server, setting the content of the request as XML, and then sending the XMLDOM. Any result is returned via the XMLHTTP object's ResponseText property, which is subsequently loaded in the XMLDOM and analyzed for any error messages.

If no errors are detected, the update has succeeded and the procedure ends. However, if there are errors, the text of the error message is parsed and included in a user-defined Error so the TableUpdate function can see the failure. Without this code, your TableUpdate call would always return success, even though there might be a problem.

To test this code, execute the caXML program, make a change to one of the fields in the cursor, and then issue TableUpdate from the command window. If TableUpdate succeeds, you should be able to see your change on the server. However, if TableUpdate fails, you will need to use the AError function to retrieve the error message generated by SQL Server.

If you are curious about the contents of an UpdateGram, you can step through the UpdateXML method of the class and check the contents of the UpdateGram property once you are inside this method. However, if you're not in one of the data modification methods (as specified in the UpdateCmd, InsertCmd, or DeleteCmd properties), you cannot see the contents of the UpdateGram property.

Listing 6 shows the contents of an UpdateGram when the ContactName field has been changed on the Customer record with the ID of 'CACTU'.

As you can see, SQLXML can read this document and easily build an Update-SQL statement, which it then posts to the SQL Server. The updg:sync element is closely related to starting a transaction; therefore, if you have multiple tables to update, you could combine them into a single UpdateGram, ensuring they are encapsulated within this element, and they will be wrapped within a transaction.

Final Thoughts
In this article, we've covered a lot of ground, showing the four "faces" of the new CursorAdapter class. You've seen how to build the CursorAdapter through the DataEnvironment and CursorAdapter builders, through the visual class designer, and through a PRG. You've also seen the basics of building CursorAdapter classes for native, ODBC, OLE DB or XML data access, and how to make each one of these classes updatable as well.

The next step is to think about how to apply these classes to your everyday development efforts. In my opinion, I can see the CursorAdapter class working very well in the UI layer of any application, and also in certain kinds of business objects where there is lots of processing code to implement. The CursorAdapter, as noted earlier, is not a good choice of object for passing data between tiers, as it converts everything into a non-portable VFP cursor.

However, in a scenario where a business object uses a CursorAdapter class, it can receive the data from the data source, and then process that data using standard VFP commands and functions, since it is in a VFP cursor. When finished, that data could be converted to a more suitable type for cross-tier marshalling, such as XML.

The other advantage of the CursorAdapter is the common OOP interface, regardless of the type of data that it accesses. Even with the XML version, which requires the most coding to make updatable, we still retrieved the data using CursorFill, updated data with TableUpdate, and retrieved errors with AError, as with every other type of CursorAdapter.

With a little forethought and planning, you could conceivably build a reusable set of classes, based upon the CursorAdapter, that could then be tweaked for each individual data source. These classes could be reused between applications or mixed within the same application to standardize the way your application handles data.

Chuck Urwiler is a Senior Developer and Consultant with EPS Software Corporation, where he develops applications using Visual FoxPro, VB.NET, ASP.NET, XML, and SQL Server. Over the past several years, Chuck has provided training for thousands of developers as well as designing and implementing mission-critical applications using Microsoft tools and technology. He continues to share his knowledge with the developer community through presentations at user groups, Microsoft seminars, and Developer Conferences for VFP, SQL Server, and .NET. Chuck is a co-author of Building Client/Server Applications with VFP and SQL Server by Hentzenwerke Publishing and has served as a technical editor on several other books regarding SQL Server, MSDE, and e-Commerce. Chuck is a Microsoft Certified Solution Developer (MCSD) and a Certified Database Administrator (MCDBA). You can reach him at chuck@eps-software.com
Thanks for your registration, follow us on our social networks to keep up-to-date