Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Problem accessing cutom class method 1

Status
Not open for further replies.

Paco75

Programmer
Oct 11, 2001
239
US
Hi,

I created a custom class witch contains a collection of another custom class.

So it looks like this

Code:
myClass
   && Attributes
   subClassColl && Contains a collection of mySubClass
   
   && Methods
   getSubItem && Gets the sub item at index n from subClassColl

myClass.init
Code:
&& myCollectionClass is a class with Collection as Baseclass
this.subClassColl = CREATEOBJECT("myCollectionClass")

myClass.getSubItem
Code:
LPARAMETERS idx
RETURN this.subClassColl.Item[idx]

When i want to access a subItem i do like this
Code:
&& myClassList is a class with Collection as Baseclass contained in my Form. 

&& To get the first item by example if i do the following it says getProduit is not a member of myClass 
thisform.myClassList.Item(0).getProduit(0).Code

&& but if i do the following i can access the subclass property
thisform.myClassList.Item(0).subClassColl.Item(0).subProperty

why my method is not visible in runtime? I set it as public so it should be in the code scope.
 
in the las code box i mistyped my example... you should read :
Code:
thisform.myClassList.Item(0).getSubItem(0).subProperty
 
So replace the las code box with this one

When i want to access a subItem i do like this
Code:
&& myClassList is a class with Collection as Baseclass contained in my Form.

&& To get the first item by example if i do the following it says getProduit is not a member of myClass
thisform.myClassList.Item(0).getSubItem(0).subProperty

&& but if i do the following i can access the subclass property
thisform.myClassList.Item(0).subClassColl.Item(0).subProperty
 
Item(0) is an object from a collection, right? And you want to use Item(0).getSubItem(0) to get another object from it's collection, but now via a method getSubItem(), right?

While the syntax is the same, the 0 in Item(0) is just an index, while the 0 in getSubItem(0) is a parameter passed to a function. As VFP is not strong typed, this will never work, the parser doesn't understand this would return an object. You need to take a step like this:

Code:
oSubItem = thisform.myClassList.Item(0).getSubItem(0)
? oSubItem.subProperty

or even

Code:
oItem = thisform.myClassList.Item(0)
oSubItem = oItem.getSubitem(0)
? oSubItem.subProperty

For the same reason you can't write code like this:

Code:
o = CREATEOBJECT("ScreenGetter")
o.GetScreen.Caption = 'Test'

Define CLASS ScreenGetter as Custom
   Function GetScreen()
      Return _Screen
   EndFunc 
EndDefine

Forget about such jumps through hoops.

You need to use VFP the VFP way, not the Java or .NET way.

What are you really trying to accomplish with this? Objectifying records in a Collection? Like LinQ to Objects in VFP instead of using Cursors? What are the subitems? Forms? Records?

Bye, Olaf.
 
Hi Olaf,

Thanks for your answer.

Yes i want to Objectify records from a production order into an objects collection. I wish to place records values in a objects structure so that it could be manipulated easily. The objects structure represents a produced item with all options selected by the salesman.

thanks again! :)
 
Use Cursors, don't make collections of record objects.

Once you loaded the data you want to let your salesmen edit, you can set a relations between them, for example.

Controlsource, Rowsources, Recordsources can all be set to aliases and field names, no need to change a cursor into memory variables or obbjects.

Buffering enables you to keep all changes in that buffer memory. It makes no sense from the outset of what VFP controls offer to go for record objects and collections. Don't go that route.

Bye, Olaf.
 
Hi,

In case you realy want to make an object of your records, I would advise agains it and second Olaf in this, use the scatter / gather commands, with parameter Name.
Regards,

Jockey(2)
 
Jockey,

I think Paco is already doing so, how else would you generate record objects than with SCATTER NAME? Record objects are nice in single instances, but adding a layer of collections, you have very limited use for them, eg for filtering, querying from them, sorting, you have much better options with cursors.

A single record object can be passed on, typically a child form will just need the id, though, to find that record in either the shared datasession or reopening a table/view/cursoradapter cursor, navigating to that record.

I do use record objects stored into nodes of an activeX treeview for easy access, but that is because of the treeview, as it's not able to work with foxpro cursors. In the end even with that object oriented treeview, I put changes back into cursors and use TABLEUPDATE() as the central command to save any changes made in buffers. And I keep the cursor buffers in synch with treeview nodes as far as I can, not just before saving. So even with ActiveX controls I do maintain the in memory data in cursors. It's just nice you can pass on objects with all their properties to a COM component, still the nodes columns need to be filled with the individual field values, unfortunately.

And on the VFP side only combobox and listbox support a RowSourceType of Collection, even just a plain Textbox does not. Not to speak about the Grid. And repeat: Talk about seeking, filtering, sorting a collection. This makes no sense.

Collections are fine for other things, eg to contain all references to forms running or other such references to a collection of things you otherwise need to adress very individual in their object hierarchy.

Bye, Olaf.
 
The main purpose i am doing this is to be able to encapsulate methods and functions to the corresonding object representation... how could i achieve this with cursors?

It is an old program originally made back in the time of foxpro 2.0 by non-programmers (i suppose) updated and maintained trough following versions of VFP up to VFP9. The tables i want to put in that object collection is stored in individual tables (one by order) and is written in a human readable form (dont know why) so i cant use scatter/gather... i wish, but cant. Think of a table you can read as a report o_O

I want to be able to parse it and store it in a object structure to be able to do such things as following.

myPurchaseOrder.parseOldFormat()
myProduct.getWidth()
myProduct.getPrice()
myProduct.hasThisOption() or myProduct.hasAnotherOption()
... etc
myPurchaseOrder.saveToDataBase()

I want to structure this that way because after the bad table structures the second biggest problem we got is lots and lots of redundancy in the code tied to buisness model. When we want to update something we have to review/modify frequently up to 10 forms repeating the same modification with some variants occasionnaly.

Maybe its because i have a Java background i am thinking in objects this way. If you explain a bit more the cursor solution you are proposing i am ready to listen.

 
OK, I see, more than just a record collection, you want the objects to have their own functionality related to their own data, as in "living records", knowing what they are and what they can do or what methods they offer others (parent/child records) to do with them.

Well, you can have such classes encapsulating these functionality referencing data via their own "private" alias or aliases instead of collection. I can understand you think of this as bad encapsulation, if the objects data is not in itself but in seperate cursors, but that's an approach you would need to change with foxpro.

If sticking with such classes/objects you would be better off really attaching children to their parent obejct via Addobject, ending with oORder having oOrder.oOrderDetail1, oOrder.OrderDetail2 sub objects.

But I would rather only store an alias name of a cursor and an ID in each record object and let it reference it's data that way. You can't have protected fields this way, but that's what they also are not persisted on the DBF level, anyway.

I come back to this and show you an example using the northwind database orders and orderdetail tables, if you don't mind waiting a bit until the weekend.

Bye, Olaf.
 
That's ok it's a side project im doing when i have time. I will wait your example. Thanks!
 
Hi Paco,

let me get to the first part today.

The typical VFP frameworks you find will rather have dataaccess and business logic classes, that will not handle single records, but will handle one or even more tables and all data loaded. It's more natural to keep the code on data seperate from the data, also within memory. So cursors already are the abstraction layer from the tables in regard of the data itself.

In this part of the answer I want to show you why to do rather that, than to go for record classes. Once you know how you can link aliases and it's records you will not have the need to put these into objects to link them via object references.

So this will give you the first hint on why putting data into an object hierarchy is not the VFP way.

Code:
Clear
Close Tables All
Close Databases All
Set Exclusive Off

Open Database (_samples+"Northwind\Northwind.dbc")

Use Orders In 0 ORDER orderdate 
Use OrderDetails In 0 ORDER Primarykey && it's an index on Str(orderid)+str(productid)
* By the way: This actually is bad design, 
* each table should have a seperate primary key field 
* with no other meaning than to identify a record.
* Normally would set order to a foreign key here.

* set up relations and skip
Select Orders 
Set Relation To Str(OrderID) into OrderDetails && because of the bad table design of orderdetail 
Set Skip To OrderDetails && will make skip (or scan) in Orders first skip in Orderdetails (as if data was joined 1:n into one alias)

* navigting data

* 1. Selecting an order
* Notice, OrderDetails automatically is positioned to a first orderdetail in the order
? 'GO TOP in an Order'
Indexseek(10251,.T.,"Orders","OrderID")
? Orders.OrderID, OrderDetails.ProductID

* 2. Scan Order and Orderdetails via relation/skip
* Notice, that the Order s listed with all Products from OrderDetails
?
? 'Scan one Order including all OrderDetails'
Select Orders
Scan For OrderID=10251
   * will scan three rows, as there are three orderdetails of orderid 10251
   ? Orders.Orderid, OrderDetails.ProductID
EndScan

First I have to state, this actually is a very old and outfashioned way to go about loading and navigating data. It's not very scalable to USE tables and navigate to a certain head data and it's children this way.

Not only USE but also RELATIONS and SET SKIP are oldfashined and less scalable than SQL Queries joining data.

BUT:
When you create classes on top of this, that would load a single order (and it's child data) and index and relate the loaded data this way in memory (in cursors), this oldfashioned way of a kind of "live" sql join will be scalable again, as you only apply it to a small part of the data.

These classes on top of this is what I will add in the next part, later perhaps, or next week.

As you can link the data itself this way, the need to load the data into properties of record objects and link them via object references is gone. Because data is already linking each other, there is no need to reinvent that via record class instances. Why would you want to put each record into an object, if you can adress records this way already?

Also the code you would put into a record class is the same for each record instance, so why create many instances of classes, if one could do the job alone? You only need one order class and one orderdetail class to have the code for the records in memory.

So the idea I will show next time in code is to have record handlers, which can work as the record objects you intend to do anyway, by navigating to some ID, before handling that single record. So instead of 5 orderdetail objects I will aim for an orderdetail record handler, which can navigate to any of the orderdetails of the order loaded and handle it.

The data of each orderdetail is still kept seperate in the orderdetails alias, so we keep program and data seperate. The orderdetail handler also enables you to handle seperate records but also all detail records at once. You would not need to cascade a call to compute a sum to all orderdetail record objects each one adding itself into a total sum, the orderdetail handler would simply sum all it's orderdetail records.

On top of that I think of an overall handler or controller for orders in the sense of the real world objects, handling all order data. It will be a controller of the two record handler classes.

The controller will encapsulate the knowledge about the structure of an order in the database. For example it would load an order by letting the order record handler load it's head record and then let the orderdetails record handler load it's details for that order. Also, the controller would handle the relation and set skip and would be used to navigate the data and to steer how data is saved. Especially it would start and commit or rollback a transaction of saving order and orderdetails via steering the record handler objects.

Would that be an idea?

Bye, Olaf.
 
Hi Olaf,

Interesting. I got the general idea. But i dont know if this would lead to "easier to maintain" code, for now i see them as same difficulty level (wich is a lot better than what we have now). I will wait your next example with records handlers.

Also you must note that tables i got are actually free tables without primary keys and not indexed. And i could say that pretty all tables got no idField identifying a single row. But anyway i wish to create new database so it would be the opportunity.

thanks again, i wait your next sample! :)
 
Hi,

I got a cold now, so I will be off for a bit.

My understanding is - but I may be totally wrong on this - that you nortmalize data with code you have in myPurchaseOrder.parseOldFormat()

So that's where you also can generate cursor data with ids and indexes in addition to recordhandlers but instead of record objects.

That would be the idea, of course in the long run you will put data into a good normalised database schema.

Bye, Olaf.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top