Refactoring: VFP form calls external PRG, uses Publics for shared data

I’ve inherited another legacy VFP application and am updating a routine to use a new format required by my client’s customer. There is a VFP form that eventually calls a program to gather, format, and export relevant data. One of the first things I need to do is change the form and program so their code can be independently tested. Once that’s accomplished, I’ll change the routines to generate the new format.

The question is, as always with this common situation is whether to pull the code into a “blob” method in the form and change all variables to properties, or call the program from the form with parameters. I realized my usual inclination is to use the former because eventually I would be binding the form properties to properties on future business classes that I’d create down the road. It’s odd how I’ll suddenly think of a usual problem in a different light. This is a routine that’s run four times a year, the new format is needed soon, and the client wants to begin planning for a new application to replace this one. Visual FoxPro will probably not be the tool of choice, so there is no reason to build the Queen Mary when a dinghy will get us across the narrow inlet just fine.

Can you tell I’m prone to make everything into A Work Of Art? Maybe I’m changing after all.

Advertisements

Get Stuff(ed): formatted Datetime string

ETA: 2009.12.02: This code is in version 8. As the inimitable Doug Hennig (fangirl squeal) points out in comments, VFP 9 TTOC() has a new flag for returning an XML DateTime format. I would still use one of the options below because they are version-neutral, and because Set Date Short | Long affects the return value (the setting from Windows Control Panel is used).

Well, that and because sometimes one simply must write code that makes one giggle.


Silly, but this code amuses me.

? Stuff( ;
  Stuff( ;
  Stuff( ;
  Stuff( ;
  Stuff( Ttoc( Datetime(), 1 ), 13, 0, ':'), ;
  11, 0, ':'), ;
  9, 0, ' '), ;
  7, 0, '.'), ;
  5, 0, '.')

ETA (2009.12.02): Another way to do the same thing as above is the following:

?Transform( Year( Date() ) ) + "." + ;
  Padl( Transform( Month( Date() ) ), 2, "0" ) + "." + ;
  Padl(Transform( Day( Date() ) ), 2, "0" ) + " " + ;
  Padl(Transform( Hour( Datetime() ) ), 2, "0" ) + "." + ;
  Padl(Transform( Minute( Datetime() ) ), 2, "0" )+ "." + ;
  Padl(Transform( Sec( Datetime() ) ), 2, "0" )

*Yawn*

DefaultValue (VFP-to-SQL Server)

File this one, too, under the category “blindingly obvious…at least in hindsight” in the never-ending VFP-to-SQL Server saga.

Balancing up front cost and with cost of a change: use DefaultValues. For every field.

The end.

ETA: Be aware, the upsizing wizard doesn’t seem to carry over the DefaultValue property when it creates remote views on data.

DbgetProp( cName, “View”, “Tables”) fails…more often than I thought (VFP 9.0)

In an earlier post, I noted what  I thought was an anomoly: DBGetProp(cName,”VIEW”,”Tables”) unexpectedly returned an empty string. I rebuilt the view, and since it seemed to be an isolated issue in a view that had been around for years, I dismissed it as a glitch. Today I’ve discovered it again in a view I’ve been modifying. I don’t know at what point the DBC stopped recognizing all the tables, or even if there is expected, albeit inconvenient, behavior. The documentation sure doesn’t seem to cover it.

Is it an unreliable command? Or am I misusing it? Or just misunderstanding it? For now I’ll have to assume it’s unreliable and hard code the constituent cursors in the interest of moving along.

Phooey.

DBGetProp fails (VFP 9.0)

Ugh. Ever have DbGetProp( cViewName, “VIEW”, “TABLES”) return an empty string? Yes, the view is really a view, in the current database. Works perfectly fine in every regard. (It’s a very simple query that selects the year of a date field, and groups by it.) One table. One field. Weird. Took out the year function, and the DbGetProp still returned blank.

Rebuilding the view fixed it. But, um, what the hell?

NoData, requery, and views of views (VFP-to-SQL Server)

I’m working on a project converting a client’s VFP 9 data to SQL Server. The VFP app uses local views (via data objects) that use native VFP data and local views. Swapping the native VFP data for SQL Server data isn’t as simple as redirecting a view from a DBF to a remote view. I should have realized this since, as I well know, VFP doesn’t automatically requery underlying views.

Say I have a view on a People table that selects the last name–call it lv_PeopleByLastName. It’s trivial to redirect the view to query remote data instead of local data. But if I then use lv_PeopleByLastName with NODATA, the remote view is also opened NODATA. That makes sense. The gotcha is that requering lv_PeopleByLastName does not also requery the remote view. So, even after Requery() the local view will still be empty since the remote view is empty. One must requery the remote view, then the local view.

IOW, once open every data source operates independently. VFP doesn’t automagically maintain dependency info about an open datasource (except through the database container, of course).

This should not have surprised me. It’s not fatal, just a complication I should have foreseen. So, I can’t simply redirect a view from local data to a remote view without changing either the views or the way dataobjects manage requerying.

Here are my options as best I can tell:

  1. Change the views so they don’t use other views. To be frank, SQL syntax and I are not BFFs. I’d rather stick a fork through my hand than work as a database manager. SQL feels like one is writing entire programs in a single line of code–the antithesis of maintainability. So, I like SQL streamlined as much as possible. Luckily most queries are fairly straightforward.
  2. I could rework the data objects and the views so that data objects cascade other data objects representing underlying views that would be requeried whenever the parent object is requeried. Okay, I confess. I just threw that in there because options should always come in threes.
  3. The data objects could make note of what underlying views are involved and requery them when the object is requeried. That works. It’s not elegant, but it is effective, and considering the bottle neck is generally fetching remote data, doesn’t add significant processing time. However, if more than view uses the same underlying data, it could make for some unnecessary requerying.

It looks like option 1, with option 3 held in reserve. Which I could have had done by now instead of posting. But I’ll call this organizing my thoughts rather than procrastinating on the inevitable.