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 gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Online Counter Update

Status
Not open for further replies.

irfanhabib

Programmer
Feb 17, 2016
16
PK
Respected Experts,

First i am very thankful , this forum support me every time and
i appreciate very quick response.

This moment i face another problem , actually my coding in following prg
file.

***** counter.prg

set talk off
set echo off
set safe off
set date brit
set cent on
clear all
clear


do whil .t.
close all
Sele A
use Cnfile
inde on cuscnt to cs1
set orde to tag cs1
go bott
A=0
A=cuscnt+1

Sele B
use Customer
inde on cuscnt to cs2
set orde to tag cs2
go bott
SCAT MEMV BLAN

@ 2,40 say 'Customer Id : - '
@ 2,55 say allt(str(A))

@ 5,40 say 'Customer Name ' Get M.Csname
@ 7,40 say 'Business Address ' Get M.Csadd
@ 9,40 say 'Mobile #' get M.Csmob

op1=0
@ 12,40 get op1 func '*p save;re-input;main' size 2,10,1
read cycle

if op1=1
sele a
go bott
appe blan
repl cuscnt with a

sele b
go bott
appe blan
gath memv
repl cuscnt with a
loop
endi

if op1=2
loop
endi

if op1=3
do main.prg
endi

endd


My Requirement :
================
1. Multiple user run this prg file ( i create link on each user pc on desktop )
2. When User run this application every time counter number display according
to index serial
3. if multiple use run this application on real time counter name update as per
user timing with any duplication.
4. if one use enter in this application and he exit without saving counter series
automatically ordered if any other user working on input fields.

Important : I know many expert feel this is type of query not entitle for this
professional forum , but in my present home town, no high qualified
professionals and institution available , so sorry in advance if anyone
feel negative or unprofessional regarding my query.

Note : I humbly requested kindly provide me solution in prg coding ,
i already mentioned previously i have no idea regarding form base
programming.

very best regards
irfan habib
















 
First of all this should be posted in forum182

I'll try to answer anyway, not really understanding your english I think you want a counter to never generate a number twice and also to have a series of numbers without gaps, even if users revert or cancel a new entry. It's easily doable to have a series without double values using Integer AUTOINC, unfortunately not available in legacy Foxpro.

The line doing your count must be A=cuscnt+1 and even without knowing, whether cuscnt is a field of a table or a variable you initialise elsewhere, this is not updated immediately, only A is assigned the next value, so any additional user reading cuscnt+1 will potentially get the same value.

Very generally speaking you have to increment that counter when reading it already, not only A has to contain cuscnt+1, also cuscnt itself has to be incremented. To have this increment guaranteed only from this current user session you have to lock the record, increment it, take and store that as next value and unlock. Any user not capable to lock has to wait, as it's only certain he gets the correct current value, when the record is unlocked again AND he can lock it, only that way you read the value exclusive.

That way to work with a counter does also tell you it's impossible to put back unused numbers. If two users get customer numbers 1027 and 1028, if at all only the user having the 1028 could revert it and decrement the counter. If the user with 1027 cancels out, there is no way to let the counter be reverted to 1027 and then still skip 1028 next time. At least you would need to apply double checking, whether a number already is taken by seeking in the data, and even then you can't check buffers. Ways to overcome this would be having a table with next values you can grab from and put back to. I've done this and it even wasn't fullfilling all customers wishes, as more things are attached to this. Eg if a number label was printed, it was printed, there is no way to revert a physical object.

So what you can do with a centrally available counter is generate unique values, that in the normal case are a series of numbers, even without having the autoinc feature available.

The process is to USE the countertable, LOCK. If successful increment, REPLACE and finally UNLOCK, if unsuccessful wait and try lock again, eventually give up after a timeout. what you can't have is the counter in the last record of the customer table, as that is typically buffered per user and each one doesn't see into the buffer of any other user, so you can't guarantee seeing the last value, even with GO BOTTOM. This counter has to go into a separate table, eg with one record only or one record per table with such a serial number.

And to make things clear, also the autoinc is not providing the feature of gapless numbers, it's updated in the same manner, it's just not stored in a record but in the table header and the process of locking and updating that is maintained by VFP.

Bye, Olaf.
 
Dear Sir OlafDoschke

presently i used vfp version 6 , i read your expert advice. I only want if multiple users

execute my prg, than field variable cuscnt of database cnfile automatically allocate unique serial

number of each user , based on last saved numeric number present in database cnfile, and if user click on

Save button all field data saved and both database updated. But if user click on Exit button than field variable

cuscnt of database cnfile auto refresh and update as per current numeric order , and other users if working ,

serial counter auto-adjust as per current numeric order.

Sorry For My Weak English.

very best regards
irfan habib



 
Well, isn't that what the code does? Where does it fail to do what you want?

Bye, Olaf.
 
If you are going to be using "vfp version 6" (or a more recent version such as VFP9) then you should no longer be using the OLD code approach containing lines like: @ 5,40 say <whatever>

Go to: and spend some time with the Free VFP Tutorial Videos learning how to use VFP6 (and later) to make Forms, etc.

Also you explain what you want to do, but maybe you should explain WHY.
Perhaps what you want to do is not the best way to get what you want to achieve.

Good Luck,
JRB-Bldr
 
Beginning to use Windows Forms is no solution to a serial number generation problem at all and while it would bring the whole application to a level easier to maintain and extend, it's not an instant solution at all. For an easy automaticall incrementing autoinc value the app should even be migrated to VFP9, it's not even an expensive solution, if compared to a few hours of freelancer developer you can only get for this.

But the code does alreedy increment cuscnt via [tt]repl cuscnt with a[/tt]

Bye, Olaf.
 
@Irfan, As I understood, you are incrementing Customer ID before showing to user.

Better option

1. Show Customer ID to user if necessary suffix by "(Provisional)"
2. When you save customer, lock the table/record and get ID from table. Increment it and then replace then unlock table.
3. Show again to user which ID user saved.
 
1. Show Customer ID to user if necessary suffix by "(Provisional)"
2. When you save customer, lock the table/record and get ID from table. Increment it and then replace then unlock table.
3. Show again to user which ID user saved.

I don't see the point of temporarily showing a provisional ID. It can't serve any purpose, and will only confuse the user. Better to wait until you have the actual ID.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
There's too much guesswork to do here about what tables structures are, what environmental settings are done (eg is buffering used or not) and much more, I'd say anyone wanting to give a decently safe version of the code adapted to multi user will need hands on this and data.

Bye, Olaf.
 
Respected All Experts

i am very thankful if any expert provide me proper source
code in prg file format. Actually i start my first job and
on startup i face this problem , if i am not fix this problem
ASAP, may be my job not continue in future.

i am only one person to support my family, i humbly requested
kindly support me and help me regarding this problem and provide
me any suitable solution.

very best regards
irfan habib
 
irfan habib said:
provide me proper source code in prg file format.

In general, we are not here to GIVE you code.
We more generally provide Advice and/or Suggestions to you so that YOU can develop your own code.

And this is especially true if we don't completely understand what you want to do nor WHY you want to do it that way.
Quite often we have other possible approaches which can get to a result in a better method.

Olaf's comment is accurate: "There's too much guesswork"

Good Luck,
JRB-Bldr

 
In general, we are not here to GIVE you code.

Of course that's right. It's difficult enough to provide bug-free efficient code when a client specifies in detail what they want. With a vague statement like we have here, it would be impossible.

Mike



__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
I'll just formulate it differently: Even though I'd like to provide a solution just having current code and a general idea what you need, this is insufficient to make sure the code I write will work in your environment. Often it's not enough to see partial code to fix or extend it, but you need hands on, meaning complete code and data files.

Please set break points in this code and execute it step by step, try to identify where it differs to do what you'd expect and want and then see how to fix it. If two users doing this at the same time play a role, simply use two Foxpro sessions and debug in parallel, that's totally doable.

Simply click left beside a line to create a break point, it'll show as a red dot, and when you start the prg this is where the debugger will start and allow you to execute line by line.

Bye, Olaf.
 
This is just a continuation of the Guesses we are having to make in order to try to assist you.

If the purpose of your wanting to get some number to represent the separate users instead you might want to get their workstation login name instead of some generated number that has very little meaning.

For Example:
Code:
cUserName = SYS(0)
cUserName = ALLTRIM(SUBSTR(cUserName, AT("#", cUserName) + 1))

You can capture any user's Start Time when they log onto your application with:
DTOC(DATE()) + " " + TIME() and store that into a Character field​
or
build a string like: {^yyyy-mm-dd hh:mm:ss} and store that into a DateTime field​
And you can capture the End Time as well in a similar manner - all without needing to use a constantly running Timer.
Plus you can capture interim times by capturing these Date + Time combinations at various entry points into your Application's various functions.

Olaf is also correct when he says: Beginning to use Windows Forms is no solution
But you have said:
Code:
i already mentioned previously i have no idea regarding form base programming.
That is why I suggested above that you spend some time learning how to use Visual Foxpro 6 (and later versions) to learn this.

Another suggestion:
irfan habib said:
i create link on each user pc on desktop
Don't put your VFP application EXE on the Server and then put links (shortcuts) to it on the individual workstations.
Instead put the VFP application EXE's on the individual workstations themselves and have them 'point' to the Data Tables which are on the Server.

NOTE - we are trying to help, but we are merely GUESSING on what you are trying to achieve.

Good Luck,
JRB-Bldr
 
Dear All Experts -

initially i fully tried i solved this problem at my own side , when i failed than i paste

my prg code, for experts best advice. ( VFP6)

My Points
================

1. Three different user execute my prg file on real time.
2. Separately allocate three different numeric counter number for each user ( numeric number auto index )
3. if starting two user quit without saving than last user counter auto adjust before saving in master database.

very important last user counter no is : 03 , when starting 2 user quit without saving
than current user counter number auto adjust or replace real time basis, and finally
system allocate counter no : 01 for last user before saving in master file.

very best regards
irfan habib




 
You can't display an ID, that automatically adjusts upon the quiting of another process on another computer.
You would need to implement a message queueing system which would be overly complicated.

What is quite easy is just incrementing the count, when you're sure you save, then you don't display the number of a new record, before it's saved, you specify TBD (to be determined) instead. You want to take the max+1 number in case of saving only and at the time of saving only, to avoid gaps, and so you only know that number at that moment.

Besides: Assume you get this done and you have code telling any other user to decrement their not yet saved numbers. What happens, if any other program crashes the computer of a user or the process gets terminated by task manger? Even if you have a stable messageing implemented, in such a case this won't inform the other PCs. There is no solution to display an ID as it might be and wanting it to auto adjust before knowing if other numbers will be used or not.

Another scenario not working: Users have computed customer numbers 001, 002, and 003. No user quits, but the user with number 002 saves first, Now if the user with 001 quits you still have a gap. To avoid the gap you would not only need to inform the user with customer number 003 to decrement, but at the same time also decrement the used number 002 to the now free 001. And later the user knowing his customer was saved as 002 is not finding it with that number. And that's the final thing you never will get to work. Would you really know which user to inform at next start up, that his customer 002 is now saved as 001, because a collegue did not use the 001 he got assigned?

And what if the user with customer number 002 not only saved that customer, but also already entered an order and mailed the order confirmation with customer number 002? That number now is in the wild, it's final now. The user quitting with customer 001 will cause a gap you can't close, and if you want to display the customer number at beginning of entering it, that's what you'll have to live with.

You see, there are very many reasons the mere idea is faulty, even if it would work to implement an intelligent and stable messaging system. The only realistic and simple solution is to determine the number in the moment of saving and telling the user who saved the definite and final customer number. Or you determine the number upfront not yet knowing it'll be used definitely. Then you accept the gaps caused by users quitting. You can't know previous to that save moment, who will really save first or at all.

Next problem, what about deleting a customer later? Would you close gaps in that case? Any already printed orders or bills can't be adjusted. You can see a gap caused by not saving a customer in the same way as a gap caused by deleting an old customer, it's an acceptable thing. Totally acceptable and normal.

Bye, Olaf.
 
Code:
there are very many reasons the mere idea is faulty

Now that Olaf has correctly identified all the various ways in which what you are trying to do Will Not Work, rather than trying to explain what you hope your code will do - why don't you tell us the Purpose of What you are trying to do.

Once we understand the Purpose of What you want to do, we might be able to better assist you by suggesting different approaches.

Good Luck,
JRB-Bldr

 
Dear All Experts -

I am very thankful yours quick and valuable advises.

My Need
=======

I design data entry screen based on following two shared databases.

1. Cnfile.dbf
2. Customer.dbf

1. Cnfile.dbf
=============-
only one field present in Database CNFILE.dbf ( Fieldname : custno ) above field index and
i use this field for unique index counter number , based on bottom record of dbf file, when
multiple or single user execute this prg on real time, control pick last saved record value
and increment plus one +1. ( A=custno+1 )

2. Customer.dbf
===============
After +1 increment , current numeric value display , if single / multiple users execute this
prg on real time control allocate unique counter value for each user , and remaining inputs
fields display.

Problem
=======
Last bottom record value is 3, when single / multiple user execute this prg control allocate
value 4 for single or multiple user, i understand last value in bottom record is 3 after increment
of plus one +1 , control allocate value 4 for all users.

i think i design one more database and this database control active users counting , every time
when user execute this prg , active database counter add increment plus one +1, and paste value
after appending new record in same dbf.


regards
irfan habib


 
The solution you think of isn't solving your problem. And you still don't say what you want to achive, what are your priorities?

Even after you solved the problem of all users seeing the same A (you update cnfile far too late, thnis has to be done instantly) and you get User a,b,c get different custno values, you still have the problem that a user cancelling/quitting disturbes ALL other users and that's what's never working. You won't get an update to all other users even via the files all of them are connected to, the DBFs. You would need to reach out to the variables A and you only have control about the DBF fields, not about another users A variable. So if you would get anything to work, then the process of all users have to repeatedly check, whether the A value they originally got is still valid.

The part of getting the same A is easily solved and has been told already, you instantly update cnfile.dbf after you read from it, doing that at the end of your code is far too late.
But even if you change that, you still have lot of situations this still doesn't work out.

You can get unique numbers this way, but not without gaps. I interpret your hardly understandable sentence like that:
and he exit without saving counter series automatically ordered if any other user working on input fields.

Can you please rephrase that?

If it means what I think, then you'd need to reach out to the other users from a quitting process. Even if you disregard crashes of a program and only consider the normal case a user quits, this still means interprocess communication between different computers. This is not working out nicely.

The smartest solution is NOT displaying A until a user saves his entry and determining A at that moment only, then display to the user "The cusomter you saved ha been assigned the customer number: "+alltrim(str(A)). You don't determine A before starting the @says, you determine it after the user chose the save option and only in that case.

Bye, Olaf.
 
irfan habib said:
control allocate unique counter value for each user
irfan habib said:
control active users counting
irfan habib said:
if single / multiple users execute this prg on real time control allocate unique counter value for each user

Why not begin by telling us why you Want To or Need To COUNT the users.
* Are you trying to restrict the total number of users?
* Are you trying to inform the users as to how many others are using the application?
* Or what?

Good Luck,
JRB-Bldr
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top