Solved

clientdataset.saveToStream problems

Posted on 2014-10-13
16
119 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
  • 10
  • 3
  • 2
  • +1
16 Comments
 
LVL 25

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
 

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 36

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
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 36

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 36

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 25

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

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

747 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

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now