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!

Filter

Status
Not open for further replies.

dexterdg

Programmer
Jan 6, 2013
85
PH
Code:
Object : cmdAdd - Procedure : Click 
SELECT * FROM tbl_configuration INTO CURSOR duplic && makes a copy for comparison
SELECT tbl_configuration && returns the focus to this table
APPEND BLANK

*!*INPUTS CS = ControlSource
this.cboCate.CS = " "
this.txtName.CS = " "
this.txtDesc.CS = " "

this.cboCate.value = ""
this.txtName.value = ""
this.txtDesc.value = ""

Object : cmdSave - Procedure : Click
answer = MSGBX("Are u sure",,4+43+256)
IF answer = 6 then 
  IF *CHECKS IF FIELDS IS EMPTY OR NOT* THEN
    MSGBX("Empty")
  ELSE 
    SELECT dupli
    LOCATE FOR dupli.cate = this.cboCate.value AND dupli.name = this.txtName.value AND dupli.desc = this.txtDesc.value
    IF FOUND() THEN
      SELECT tbl_configuration  
      MSGBX("Duplicate")
      GO BOTTOM
    ELSE
      SELECT tbl_configuration
      GO BOTTOM
      *SAVE THE RECORD*
      TABLEUPDATE(.T.)
    ENDIF
ENDIF
**Buffering = 3
**INPUTS ARE CONTROLSOURCED TO A TABLE COLUMN

My problem is after the prompt of MSGBX("Duplicate"); and if the user clicks "CANCEL", the inputs are still saved even w/o TABLE UPDATE. Thou my "cmdCancel" has a TABLEREVERT(), why is that?. My suspect is the ControlSource but i dont know the work around. Ideas?

Thanks
Dexter
 
I don't see a tablerevert. You're doing a GO BOTTOM after MsgBx("Duplicate"). Why not the default messagebox()? And what exact is your msgbx Cancel Button code? Is it working in the same data session at all?

Bye, Olaf.
 
If you have Buffering set to 3, as your comment indicates, then simply moving the record pointer (as you do with GO BOTTOM) saves the changes. You need to issue TableRevert() to throw the changes away before moving the record pointer.

In general, it's a better idea to operate with Buffering set to 5.

Tamar
 
?

Ah, there: **Buffering = 3

Well, still not everything is clear. What's clear is: In the save branch, it's not the TABLEUPDATE() which saves, it's GO BOTTOM. But that doesn't hurt the program logic, it just makes the TABLEUPDATE() unneccessary.

But Dexter says, he does TABLEREVERT() in the selfmade MsgBx, when the user clicks cmdCancel of that MessageBox form.

Dexter, if you do GO BOTTOM before TABLEREVERT() in that button code, then the same the leaving of the buffered record saves it, before you revert it. For a tableupdate or tablerevert you must stay on the record you want to influence. Also my question still applies: Is your form working in the same data session at all? If not, anything you do in there is futile.

There's a good reason why using Buffermode 5 is best: 1. You can still save each record via moving on it and doing TABLEUPDATE(.F.). .F. here meaning not all rows, which means one row, but there are other parameterizations, too, see help. And the other good reason is, you can move around in the table to check for duplicates, without that saving the current record by leaving it. You already know that tricky part about record buffering, that's why you query all data into the cursor "duplic", so you can locate for a double value there.

In regard to preventing double entries the better apporach is to make use of INDEXSEEK(), especially with the parameter lMovePointer =.F., so you seek in the index without repositioning, the function just returns .T. for a found record. And since the record is buffered, it itself isn't found with INDEXSEEK, only a doublette in another record.

The third way is to define an index and let it make the restriction via being a candidate key. Then you get an error by saving a doublette, it's rejected. You can catch that error and can then revert or report back the double entry to the user. That approach sounds most complicated and indeed needs most code, but it's really the most save because even if yu do a doublette check and no matter how fast you do it and how fast you save after finding no doublette, there is this time slot where another user also saves that same thing and you still have a doublette. It's quite improbable in systems with a few users, but to prevent it you let the data decide abot the doulbettes with a candidate index. That's foolproof.

I always see developers do code to prevent errors, error handling, especially exception handling in the form of TRY CATCH really is a valid way to let errors happenin a controlled way, prevent error prompts to the end user and handle expected errors about eg such doublettes, internally. Nothing breaks, if you let errors happen and react to them, instead of doing more complicated things to prevent an eventual error. Think alone of network bandwidth. For every save you do a lookup in the index. And in your case you even load the whole data, just for checking an eveantual doublette. This is really counterproductive.

Bye, Olaf.
 
Argh! as easy as that!?! hmm.. well i got used to use record buffering(3) when manipulating a single record. And use table buffering(5) when manipulating multiple records. :) its just what buffering=3 is for right?

thanks
Dexter
 
Buffering=3 is okay, if you want that automatism of buffer commits, in the moment you leave the current record. This can be fine. You can also use the beforerowcolchange event of grids to validate the current record and prevent a user moving away from it before all rules are met. But of course life is much easier in buffermode 5.

If you don't have learned that consequence of the record buffer mode, you can struggle with errors happening through SEEK or SKIP or LOCATE and don't recognize errors happening are not directly caused by these commands, but by committing buffered data.

I also learned it that hard way.

Still, if you have code processing data record by record in a scan..endscan and don't want every single change be committed right away by using no buffering at all, the record buffer mode can save the tableupdate() line. You can of course also do table buffering and then do one commit after the data processing. But it might be essential to have data changed while going through it.

If in doubt, any feature of foxpro isn't deprecated, to allow for downward compatible execution of older code. I don't know if table buffering and the MULTILOCKS setting was introduced later than record buffering, that would explain it very well.

Bye, Olaf.



 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top