Wiki Home

Business Object Data Mechanisms


Namespace: VB
[2004.04.20] Refactored from BusinessObjectArchitectures-- Steven Black

What is a good way to pass cursors between datasessions? Or, What is a good way to return a result set (that MAY be big) from Business Objects?

My current method is:
PROCEDURE SetFilterOnDataFile( pcDataSession )
LOCAL myDS
MyDS = SET('DATASESSION')
* TempCursor contains a "special" list of ID's that are the only
*   ones I want.
SELECT * FROM TempCursor INTO TABLE (unique_generated_file_name)
SET DATASESSION TO (pcDataSession)
SELECT * FROM (unique_generated_file_name) INTO CURSOR cMyCursor
INDEX ON id TAG id
DELETE FILE (unique_generated_file_name)
SELECT DataFile
SET RELATION TO id INTO cMyCursor
SET FILTER TO DataFile.ID=cMyCursor.ID  && should eliminate all records that aren't contained in cMyCursor
SET DATASESSION TO (myDS)
RETURN

This works, but is there an easier way to pass TempCursor from "MyDS" into "pcDataSession" without writing it to disk then loading it from disk? - wgcs (ps: this is all part of a retrofit on a big project that cannot use a "SELECT * FROM DataFile WHERE EXISTS TempCursor INTO CURSOR cOnlyWhatIWant".. It has to be a filtered Table)
Hmmm. I don't know if this is usable in your context, but you could just pass the DataSessionId...-- Steven Black
I was trying to keep my example situation as simple as possible and in my editing must have taken out some explanation that I had started with. The situation is this: the default data session has oodles of files open most of the time (simple USE's of tables) in specific relationships. The Business Object's job is to take a list of rules from a rule table and use those rules to derive a list of ID's on one of the main tables, then hand this list of ID's back to the caller as a filter on the main table. The BO has it's own datasession, and the above example is my attempt to get the cursor out of the BO Datasession into the Default Datasession. It seems to me that the idea of business objects with private datasessions is unworkable if the BO has to return sets of records (it seems kludgy to have to hand a DataSessionID as a parameter, and it seems even more kludgy to have to copy a cursor to a table, switch datasessions, then copy the table back to a cursor).
Why does the BO need a private datasession? Sounds like you're arguing for changing this decision.If you must retain that approach, however, and you don't expect a massive number of IDs, you could always create either an array or, more hip, an XML string, and return that from the BO. (BTW, I hate the idea of switching sessions in code via SET DATASESSION. Seems like an ultimate kludge.) -- Randy P

You've read me exactly right: The result set is likely to be in the thousands of ID's. I am arguing (internally) whether a BO should or shouldn't have a private DS. My reason for wanting a private DS in a BO is that the BO is using a handfull of files that are going to be used elsewhere in the App at the same time: (If "owner" is not the proper oop term, please correct me)
What I use in that specific situation is a class that (1) assigns an unused alias name at run time -- storing that name to a property "cAlias", and (2) includes Destroy event method code that closes that alias if open. I don't use a private DS, since I'm protecting myself from objects getting in each others' way via my dynamic cursor/alias naming. Any other object that needs to get the BO's data can refer to bo.cAlias, for example SELECT (bo.cAlias). The alias name is determined by using a "base alias" property (say "customer_query"), and then appending a numeric suffix in a loop and checking USED() until finding an available name. This if I had 3 of these objects in use at once, they might have aliases of customer_query_1, customer_query_2, and customer_query_3. -- Randy P

The down side of private DS in a BO is that it makes getting the data back to the user object (owner of the BO) is harder: It requires passing the DataSessionID of the Owner with every call to the BO that is fetching data. The alternative I see are: (btw: this list is not meant to be only applicable to my problem above, but is trying to present many of the benefits/detriments of different implementations of Business Objects)

If you ask me, what VFP really needs is a "SET CURSOR DATASESSION TO xxx" command, or "SELECT * FROM (nDataSessionID_2):DatabaseName!CursorName INTO CURSOR CursorInTheCurrentDatasession" ... Though I just realized that neither of these solves my original problem of passing the DSID. The only thing that would would be the ability to pass cursors as the result of a Function. Imagine that, a native, object oriented cursor mechanism in VFP that treats all cursors like an ADO object, only with XBASE syntax (maybe it could even be integrated into ADO and the CLR!!! See VFPDotNet) Just make each alias a seperate object...
Imagine:
SELECT * FROM MyTable WHERE whatever=.T. INTO CURSOR lcMyCursor
RETURN lcMyCursor

It all could be organized like this:
SELECT _VFP.DataSessions(1).MyCursor

- ?wgcs

What about a method ChangeDataSessionId in Cursor Adapter (or CursorSetProp("DataSessionId", x))? Good or bad idea? The BO could return a CursorAdapter-Object and the form could import the cursor into its datasession.

oResult = BO.get(...)
oResult.ChangeDataSessionId(Thisform.DataSessionId)


Or one could make a class BO_result which is a collection of Cursor Adapters and has some functionality to handle things like this.
Where is the wishlist for VFP 10 :-)

- Kurt
Contributors: wgcs, Steven Black, Randy P
Category Middle Tier Category Data Category Business Rules Category Class Design
( Topic last updated: 2007.10.25 08:55:07 AM )