GrahamDLovell
asked on
clientdataset.saveToStream problems
I use clientdataset.LoadFromStre am to lock out other users from the file / table.
Is there a way to do the simpler, LoadFromFile, and lock out other users, by setting a parameter, or similar?
Is there a way to do the simpler, LoadFromFile, and lock out other users, by setting a parameter, or similar?
You want to lock table/row(s) in database where you connected?
ASKER
Yes. I cannot just lock rows, since I am using the client data set as my "database", so I have to load the whole table, and then save it completely.
To lock the file, I use TStream, which gives you the option to lock the file in various modes.
I would be happy with this method if SaveToStream worked, but it didn't seem to do so.
I have tried various methods, and my final workaround was to open as a Stream, and then save as file (after freeing the stream), but this seems to be a bit outside of the documentation.
If I could avoid TSteam altogether (if there is an appropriate option in the LoadFromFile method), I would be happy. I would also be happy if I could get TStream to work as expected.
To lock the file, I use TStream, which gives you the option to lock the file in various modes.
I would be happy with this method if SaveToStream worked, but it didn't seem to do so.
I have tried various methods, and my final workaround was to open as a Stream, and then save as file (after freeing the stream), but this seems to be a bit outside of the documentation.
If I could avoid TSteam altogether (if there is an appropriate option in the LoadFromFile method), I would be happy. I would also be happy if I could get TStream to work as expected.
Instead of using the VCL TClientDataset, there is another alternative. I use TKBMemTable in my product line and have never had any issues with it.
http://www.components4programmers.com/products/kbmmemtable/
http://www.components4programmers.com/products/kbmmemtable/
ASKER
Thanks for your suggestion, but I would rather resolve my issue with the native code than move to a 3rd party product.
what database type is this ?
locking a whole table is not required in most cases
If you use clientdataset on a file ...
i'm not sure that is multi-user safe.
probably not a good idea to work like that in a multi-user environment
locking a whole table is not required in most cases
If you use clientdataset on a file ...
i'm not sure that is multi-user safe.
probably not a good idea to work like that in a multi-user environment
ASKER
The database is a Tclientdataset, saved as a file.
Yes, I agree it is not multi-user safe. However, it is safe in this situation, as I only want one user to use the file. I just want to make sure he (or she) cannot open it again while that user has it open elsewhere.
Yes, I agree it is not multi-user safe. However, it is safe in this situation, as I only want one user to use the file. I just want to make sure he (or she) cannot open it again while that user has it open elsewhere.
ASKER
I have discovered my problem relates to a long-standing (not fixed) bug in TClientDataSet.SaveToStrea m.
The method calls WriteDataPacket(TStream,fa lse,Format ). It should call WriteDataPacket(TStream,tr ue,Format) , since "false" stops it writing to the stream.
Nils van der Mee has a workaround at http://www.delphigroups.info/2/67/461553.html, which involves creating a descendant procedure that sends the correct WriteDataPacket command. However, I am not sure how to implement this so that I can simply call it for all my existing cds tables.
Can I write a procedure that extends TClientDataSet, so that it just operates as an additional procedure for that class?
The method calls WriteDataPacket(TStream,fa
Nils van der Mee has a workaround at http://www.delphigroups.info/2/67/461553.html, which involves creating a descendant procedure that sends the correct WriteDataPacket command. However, I am not sure how to implement this so that I can simply call it for all my existing cds tables.
Can I write a procedure that extends TClientDataSet, so that it just operates as an additional procedure for that class?
ASKER
I have found that it is not hard to add a class helper to do this, but I don't think that Nils' post represents a solution to my problem. I have tried it, and it corrupts my data.
Back to the drawing board.
Back to the drawing board.
a file based database has one very big problem in a multi-user (multiple use) environment
> severed network connections
you need a system which keeps track of who is connected
and allows use of resources when they are free.
this comes as part of any rdbms system
clientdataset simply doesn't have this
> severed network connections
you need a system which keeps track of who is connected
and allows use of resources when they are free.
this comes as part of any rdbms system
clientdataset simply doesn't have this
ASKER
Geert
Thank you for your interest in my problem.
My application is definitely single-user, and I won't be going to a rmbs. I don't need the complication of requiring this to be set and managed, when it is NOT needed for my application. Why should I? It was bad enough with the BDE, when you had to cope with existing installations, etc., and the support complications associated with a tiny software fee. The TClientDataSet was a break through for me in installation and running simplicity.
I have tried every combination of things that I can think of to get SaveToStream to work, but it won't work.
I have a workaround - I will use that, since either no-one has had the same problem, or they have given up, as I am about to do.
Thank you for your interest in my problem.
My application is definitely single-user, and I won't be going to a rmbs. I don't need the complication of requiring this to be set and managed, when it is NOT needed for my application. Why should I? It was bad enough with the BDE, when you had to cope with existing installations, etc., and the support complications associated with a tiny software fee. The TClientDataSet was a break through for me in installation and running simplicity.
I have tried every combination of things that I can think of to get SaveToStream to work, but it won't work.
I have a workaround - I will use that, since either no-one has had the same problem, or they have given up, as I am about to do.
in your original question statement you noted this:
to lock out other users
this means you are in a multi-user environment.
you could go the old (dinosaur) way (like paradox used to do)
add a secondary file: file.lck
if the file exists, then someone else is accessing the data
keep the file open with open exclusive deny everything to any else
since you would manage this file yourself you would have total control over it.
if it's impossible to tackle a specific problem, a workaround can be a solution.
to lock out other users
this means you are in a multi-user environment.
you could go the old (dinosaur) way (like paradox used to do)
add a secondary file: file.lck
if the file exists, then someone else is accessing the data
keep the file open with open exclusive deny everything to any else
since you would manage this file yourself you would have total control over it.
if it's impossible to tackle a specific problem, a workaround can be a solution.
ASKER
My original question was imprecise. I want to lock out a single user from opening another application and damaging the data. The design should not allow "another user" access (but it could be done by a dummy with Administrator rights). I was more concerned about the program being instantiated twice (even with a different program name) by the same user.
Will you believe me now? Single User - not multiple-user.
The file.lck was an administrative problem under BDE in the event of a crash, since it was left open. TStream is easier to administer.
It looks like a work-around is required.
Will you believe me now? Single User - not multiple-user.
The file.lck was an administrative problem under BDE in the event of a crash, since it was left open. TStream is easier to administer.
It looks like a work-around is required.
I use this code for single instance - put in .dpr source file
This one will not allow to run second instance of application.
... similar code using Mutexes can be used for other lock things.
..
var
Mutex : THandle;
bAppRunning: Boolean;
begin
Mutex := CreateMutex(nil, True, 'UNIQUE_MUTEX_STRING_4_MY_APP');
bAppRunning:= (Mutex = 0) OR (GetLastError = ERROR_ALREADY_EXISTS);
if not bAppRunning then
begin
Application.Initialize;
Application.Title:=....
Application.CreateForm(....);
Application.Run;
end;
This one will not allow to run second instance of application.
... similar code using Mutexes can be used for other lock things.
ASKER
Thanks for the info on Mutex, however, TStream does the task I want done quite adequately.
Further investigation has shown that I can create a new application with the following code:
rs.cds',
fmOpenReadWrite or fmShareExclusive);
cds.LoadFromStream(StreamD ata);
cds.SaveToStream(StreamDat a);
It works fine, but when I use what I think is the same code in my larger (multi-unit) form, it doesn't work. That is, it does not write the file to disk.
Interestingly, in the small program, I can drill down in the code (while running, using F7) to the DataSnap.DBClient procedure TCustomClientDataSet.SaveT oStream(St ream: TStream; Format: TDataPacketFormat = dfBinary); and see it in operation.
However, in the larger program, I cannot drill down (using F7) to expose that procedure and to watch it in operation.
Further investigation has shown that I can create a new application with the following code:
StreamData := TFileStream.create('chapters.cds',
fmOpenReadWrite or fmShareExclusive);
cds.LoadFromStream(StreamData);
cds.SaveToStream(StreamData);
StreamData := TFileStream.create('chapters.cds',
fmOpenReadWrite or fmShareExclusive);
cds.LoadFromStream(StreamData);
cds.SaveToStream(StreamData);
StreamData := TFileStream.create('chaptefmOpenReadWrite or fmShareExclusive);
cds.LoadFromStream(StreamD
cds.SaveToStream(StreamDat
It works fine, but when I use what I think is the same code in my larger (multi-unit) form, it doesn't work. That is, it does not write the file to disk.
Interestingly, in the small program, I can drill down in the code (while running, using F7) to the DataSnap.DBClient procedure TCustomClientDataSet.SaveT
However, in the larger program, I cannot drill down (using F7) to expose that procedure and to watch it in operation.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
My original question was imprecise, which created some difficulties, for which I apologise. Other solutions were work-arounds. Only this fix actually solved the "clientdataset.saveToStrea m problem".