Solved

clientdataset.saveToStream problems

Posted on 2014-10-13
16
212 Views
Last Modified: 2015-03-21
I use clientdataset.LoadFromStream 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?
0
Comment
Question by:GrahamDLovell
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 10
  • 3
  • 2
  • +1
16 Comments
 
LVL 27

Expert Comment

by:Sinisa Vuk
ID: 40383757
You want to lock table/row(s) in database where you connected?
0
 

Author Comment

by:GrahamDLovell
ID: 40383935
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.
0
 
LVL 7

Expert Comment

by:kfoster11
ID: 40396375
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/
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:GrahamDLovell
ID: 40404220
Thanks for your suggestion, but I would rather resolve my issue with the native code than move to a 3rd party product.
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 40406043
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
0
 

Author Comment

by:GrahamDLovell
ID: 40406083
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.
0
 

Author Comment

by:GrahamDLovell
ID: 40414503
I have discovered my problem relates to a long-standing (not fixed) bug in TClientDataSet.SaveToStream.

The method calls WriteDataPacket(TStream,false,Format). It should call WriteDataPacket(TStream,true,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?
0
 

Author Comment

by:GrahamDLovell
ID: 40415016
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.
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 40415174
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
0
 

Author Comment

by:GrahamDLovell
ID: 40415237
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.
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 40415343
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.
0
 

Author Comment

by:GrahamDLovell
ID: 40415368
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.
0
 
LVL 27

Expert Comment

by:Sinisa Vuk
ID: 40417526
I use this code for single instance - put in .dpr source file
..
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;

Open in new window


This one will not allow to run second instance of application.
... similar code using Mutexes can be used for other lock things.
0
 

Author Comment

by:GrahamDLovell
ID: 40417908
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:
  StreamData := TFileStream.create('chapters.cds',
      fmOpenReadWrite or fmShareExclusive);
  cds.LoadFromStream(StreamData);
  cds.SaveToStream(StreamData);

Open in new window

  StreamData := TFileStream.create('chapters.cds',
      fmOpenReadWrite or fmShareExclusive);
  cds.LoadFromStream(StreamData);
  cds.SaveToStream(StreamData);

Open in new window

StreamData := TFileStream.create('chapters.cds',
      fmOpenReadWrite or fmShareExclusive);
  cds.LoadFromStream(StreamData);
  cds.SaveToStream(StreamData);

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.SaveToStream(Stream: 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.
0
 

Accepted Solution

by:
GrahamDLovell earned 0 total points
ID: 40669822
I found that before calling cds.SaveToStream(StreamData) I had to assign a starting position for the write operation. After that all is well:

cds.Position := 0;

Just one line of code, but endless grief!

Bliss!
0
 

Author Closing Comment

by:GrahamDLovell
ID: 40679727
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.saveToStream problem".
0

Featured Post

On Demand Webinar - Networking for the Cloud Era

This webinar discusses:
-Common barriers companies experience when moving to the cloud
-How SD-WAN changes the way we look at networks
-Best practices customers should employ moving forward with cloud migration
-What happens behind the scenes of SteelConnect’s one-click button

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Michael from AdRem Software outlines event notifications and Automatic Corrective Actions in network monitoring. Automatic Corrective Actions are scripts, which can automatically run upon discovery of a certain undesirable condition in your network.…
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can re…
Suggested Courses
Course of the Month11 days, 10 hours left to enroll

623 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question