Page 1 of 1

Get validation using database object

Posted: Fri Jan 06, 2006 4:28 pm
by wpacheco
I'm working with a database object and need to validate a get assigned to one field of the database object. Example:

Code: Select all

redefine get oGet[ 1] var oNomTra:nomtracod id 1001 of oFld:aDialogs[1] picture '@!' update
...
...
oNomTra:Blank()
...
...
nReg := oNomTra:RecNo()
oNomTra:Seek( oNomTra:nomtracod )
oNomTra:GoTo(nReg)
The question is I've noticed that if I make the search for validation propossal with this code I lost the initial value of the gets it takes the database record value. I try to assign the get's initial value to a var in order to perform the validation like this

Code: Select all

cCode := oNomTra:nomtracod
oNomTra:lBuffer := .f.
oNomTra:Seek( cCode )
oNomTra:GoTo(nReg)
oNomTra:lBuffer := .t.
but after set the buffer of the database object to false the var value is lost.
So, I need to make a validation keeping the original values of the gets

Thanks for your comments

Posted: Fri Jan 06, 2006 4:49 pm
by James Bott
It looks like you are calling the blank() method before the seek. This will refill the buffer with blank data--all the fields will be blank. I am not clear why you are calling blank()?

If you don't call blank(), turning lBuffer off, then on, should work. If it still doesn't then we need to see more of your code.

James

Posted: Fri Jan 06, 2006 5:00 pm
by reinaldocrespo
William;

redefine get oget[ 1 ] var oNomTra:VarNomTracod id ... ;
Valid (is_valid( onomTra:VarNomTraCod .... ) )

Where oNomTra:VarNomTraCod is the buffer where data is being input, Is_valid(...) is a function that recieves the inputed value and returns .t. if acceptable and .f. if not which you may later .or./.and. with a MsgYesNo stating the fact.

If clicking on Save button, then oNomTra:Save() is called which will actually lock the record and save the buffer data to the database.

Hope this helps.

If you want a generic is_valid fuction that validates info against a db, I'll post it.

Reinaldo Crespo.

Posted: Fri Jan 06, 2006 9:47 pm
by wpacheco
Ok. thanks guys... Let me explain better

My prog in first instance define some gets linked to a database object.

Code: Select all

redefine get oGet[ 1] var oNomTra:nomtracod id 1001 of oDlg picture '@!' update
After that, there is a button I use to edit the get's trought a function.

Code: Select all

redefine sbutton oBtn[1] id 1111 of oDlg name "New" nobox update ;
         caption "New" text 3 tooltip "New record" ;
         action ( NonTraEdit( "NEW", oNomTra, oBtn, oGet, oRadio, oLbx[1], oImg, oWChild) )
In the function there exist the Blank() method to allow the get edition and one routine to validate the user input

Code: Select all

function NonTraEdit( cModo, oNomTra, oBtn, oGet, oRadio, oLbx, oImg, oWChild )
	do case
	case cModo $ "NEW,EDIT"
		lNew := ( cModo = "NEW" )
		if lNew
			oNomTra:Blank()
		else
			if ! oNomTra:RecLock()
				lGo := .f.
			endif
		endif

		if lGo
		...
The same function is called by another button to validate the gets

Code: Select all

	case cModo = "CHECK"
		do case
		case Empty( oNomTra:nomtracod )
			MsgStop( "The code can't be empty", "Error" )
			oGet[1]:SetFocus()
			lGo := .f.
		case ...
		case ...
		endcase
		...
		...
		nReg := oNomTra:RecNo()
		oNomTra:lBuffer := .f. 
		oNomTra:Seek( oNomTra:nomtracod )
		if oNomTra:Found()
		    ...
		    lGo := .f.
		endif
		oNomTra:GoTo(nReg) 
		oNomTra:lBuffer := .t.
There is where the problem exist. The get initially has the user input value. I want to check if the code there exist in the database file. So, I do a search with the get value, but because the TDatabase Seek() method has a load() method inside makes the original get's value change.
If I try to set to false the object database buffer, this causes that the values are lost.
If I do the search without set the database buffer to false then all get takes the value of the database record. So of any way always I lose the original values

Posted: Sat Jan 07, 2006 2:21 am
by James Bott
Well, I still think it should work. I don't see a problem in your code so the problem must be in code we haven't seen yet.

However, I do think you are making your life more difficult that it need be. First, I suggest going to my website and reading the artciles about building database objects.

http://ourworld.compuserve.com/homepage ... rogram.htm

I will try to summarize them here.

Make a subclass of TDatabase that contains methods add() and edit(). This makes your code much easier and also allows you to use polymorphism later. In this case you are also going to need an isUnique() method (although I wonder why you don't just generate a unique ID automatically).

Code: Select all

class TCustomer from TDatabase
   data lAdd hidden
   method add
   method edit
   method isUnique
end 

method add()
   lAdd:=.t.
   ::edit()
   lAdd:=.f.
   ::load()
return self

method edit()
   local oDlg
   if ::lAdd
      ::blank()
   endif
   define dialog oDlg
   ...
   redefine get oGet ::nomtracod valid isUnique( oGet:varGet() )
   redefine button ID_OK action ::save()
   activate dialog oDlg
return self

method isUnique(cNomtracod)
   local nRecno:=::recno()
   local lSuccess:=.f.
   ::lBuffer:=.f.
   ::seek(cNomtracod)
   if ::found()
      msgInfo(...)
   else
      ::lSuccess:=.t.
   endif
   ::goto(::nRecno)
   ::lBuffer:=.t.
return lSuccess
That is the basics of it. Now you can do:

oCustomer:edit()

or,

oCustomer:add()

If you are trying to get the user to input a unique primary-key value, then I would not. For the user this is a real pain--it's like typing into a black hole. They don't know what to type and there is nothing to help them but a rude error message. I would generate sequential keys automatically.

If you are trying to get the user to type in a valid pre-existing code, then I would use a combobox instead. Better, with DBCombo, you can provide a list of descriptions and automatically get the corresponding code. This way the user doesn't even have to know the codes. The lastest version of DBCombo also has a dynamic search so the user can type in a few keystrokes to get the first match.

Perhaps something in here helps...

Regards,
James

Posted: Sat Jan 07, 2006 3:54 pm
by wpacheco
Thanks James

I think you're right but there are some events I'm considering for a technique of effective validation like pre and post validation necessary in a real multiuser environment.

TDatabase class at the moment does not offers methods to implement it. This is the reason for which I chose to post validate just at the saving time. I thought to use an inherited method of TDatabase class that does not make use of Load() when it makes the search, this way I can maintain the original values of get with no need to change the buffer data.

Of all ways thank you very much by your collaboration and time