Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

CloneCursor questions

163 views
Skip to first unread message

Yannis Makarounis

unread,
Oct 12, 2001, 10:53:35 AM10/12/01
to
I have some questions about the functionality of cloned cursors. Assume
that we have a main Cds (say MCds) and a clone Cds (say CCds).
1.. Is it true that every time I refresh the MCds I should execute
CCds.CloneCursor(MCds,true) ? My experience is that they are not
automatically synchronized.
2.. What happens when I use CloneCursor? Is there a "free", or just close?
Can I use repeatedly CloneCursor relating 2 Cds's (this is related to the
above questions)?
3.. What happens when I close a Cds, either the main or the clones?
4.. When I make changes to the CCds a Delta is created and and
ChangeCount is incremented. But these changes don't seem to affect the MCds
ie its Delta is null and when I MCds.ApplyUpdates nothing happens.
Obviously the 2 Cdss do not share the same Delta. Is there a way to
synchronize the Delta's of the Cds's (of course it can be done by passing
all the changes of the CCds to the MCds explicitly) ?
Thanks in advance

Yannis

Dave Rowntree

unread,
Oct 15, 2001, 7:51:16 AM10/15/01
to
You don't say what version of Delphi you are using.
My comments relate to D5 (I dont currently use D6) and are based on results
I have found. If anyone knows any different please jump in.

To understand ClonedCursor's it helps to understand the basic structure of a
MIDAS ClientDataSet from the viewpoint of a client app.
A cds has two levels ...
Midas.dll is the behind the scenes data engine that caches and maintains the
data, including data changes (Delta), on behalf of the client app.
TClientDataSet is the component we use in our client app to gain access to
the data in the Midas.dll.

When you open a cds, an new instance of the data (and supporting routines)
is created by Midas.dll on behalf of the cds, and a pointer to it returned
to the cds. The cds uses this pointer to obtain & manipulate data through
the Midas.dll.
When you clone a cursor, instead of a new instance of the data (and
supporting routines) being created, the existing pointer from the cds being
cloned is used by the clone. In other words, the clone points to the same
instance of the data as it's clone-parent.

Please see below ...

> 1.. Is it true that every time I refresh the MCds I should execute
> CCds.CloneCursor(MCds,true) ? My experience is that they are not
> automatically synchronized.

Not if you use cds.Refresh. The clone will be aware of any data changes from
the Refresh.
If you use CCds.CloneCursor(MCds, false) you could issue Refresh against the
clone if you wanted, and the changes will be seen by the master.


> 2.. What happens when I use CloneCursor? Is there a "free", or just
close?

Just Close.

> Can I use repeatedly CloneCursor relating 2 Cds's (this is related to the
> above questions)?

Not quite sure what you mean here but ...
You can have more than one clone on the same master.
You can change a clone from one master to another master by doing
CCds.CloneCursor(newMCds, True/False).
You can clone from a clone (CCds2.CloneCursor(CCds,True/False).

> 3.. What happens when I close a Cds, either the main or the clones?

Clones and masters 'share' (point to) the same data. So, for example,
changes made by any (clone or master) update the 'shared' data (have a
common Delta) and therefore show up in the master and all clones on that
master.
The 'shared' data continues to exist until *all* the clones and the master
are closed.

> 4.. When I make changes to the CCds a Delta is created and and
> ChangeCount is incremented. But these changes don't seem to affect the
MCds
> ie its Delta is null and when I MCds.ApplyUpdates nothing happens.
> Obviously the 2 Cdss do not share the same Delta. Is there a way to
> synchronize the Delta's of the Cds's (of course it can be done by passing
> all the changes of the CCds to the MCds explicitly) ?

Changes made to a cds (clone or not) will not show up until they are Posted.
Maybe this is what is happening.

HTH


Yannis Makarounis

unread,
Oct 15, 2001, 10:25:35 AM10/15/01
to
Thank you Dave.

During the weekend I managed to make "cloning" work the way I want it and
the way you describe. It is a great tool!
The main thing is that the Delta is common. The only problem that I have now
is that I wanted to have a master-detail relationship between 2 cds's that
are clones of another. When I post a record of the child it goes into a loop
passing repeatedly through the BeforePost event. I removed the master-detail
relationship and used SetRange instead and everything works fine.
Thanks again
Yannis

Dave Rowntree

unread,
Oct 15, 2001, 10:38:07 AM10/15/01
to
Glad you solved it.
Instead of cloning the detail try cloning the master and accessing the
clone-detail by

TClientDataSet(cloneMastercds.FieldByName('NestedFieldName') as
TDataSetField).NestedDataSet) ....


Yannis Makarounis <Yannis.M...@ace-hellas.gr> wrote in message
news:3bcaf22b_2@dnews...

Blackjack

unread,
Nov 26, 2001, 4:50:12 AM11/26/01
to
we get data through Remote Data Module,
the client use clientdataset.datarequest() to send requirment and get data
like that:
t.c.DataRequest('select * from c_message');

but now,I want this progress to be a background-progress.the code like this:

constructor TMyThread.Create(Clientdataset:Tclientdataset);
begin
inherited create(True);
FClientdataset:=ClientDataset;
FreeOnTerminate := False;
end;
.
procedure TMyThread.Execute;
begin
try
Fclientdataset.CommandText:='select * from c_message';

* Fclientdataset.Open; <- Here, an error occur: Raise exception class
EOleSysError with Message "Haven't use CoInitialize"...
*

Synchronize(StatusOut);
except
... do something here...
end;
end;


someone tell me what's happened. thanks.


Scott Price

unread,
Nov 26, 2001, 5:36:49 AM11/26/01
to
Hi Blackjack,


Opps... I see your problem.

It is a slightly more complicated thing than just that. You see your
ClientDataSet component that you are passing the Thread in the constructor
actually is owned by another Thread. You will have synchronisation issues
there.

You would need to perform all of the CDS.CommandText and Open commands in a
Synchronize protected method to get the results you are after. Example:

If you would like the example mailed to you, please drop me an email
removing the "nospam." part after the @.

Form One with a TDataSetProvider pointing to a TQuery, with the
TDataSetProvider.Options poAllowCommandText set to True. ClientDataSet2
connected to TDataSetProvider, and ClientDataSet1 showing records from the
CUSTOMER table of DBDEMOS.

procedure TForm1.btnPerformThreadQueryClick(Sender: TObject);
var
thread: uClientDataSetQuery.TCDSQuery;
sQuery: String;
begin
sQuery:= Format('SELECT * FROM ORDERS WHERE CustNo = %d',
[ClientDataSet1.FieldByName('CustNo').AsInteger]);
thread:= uClientDataSetQuery.TCDSQuery.Create(False, ClientDataSet2,
sQuery);
end;

unit uClientDataSetQuery;

interface

uses
Classes, DBClient;

type
TCDSQuery = class(TThread)
private
{ Private declarations }
{ Access to the FClientDataSet variable should only be in the
Synchronize
protected area due to it being owned by another thread! }
FClientDataSet: TClientDataSet;
FSQL: String;
procedure DoQuery;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean; CDS: TClientDataSet; SQL:
String);
destructor Destroy; override;
end;

implementation

{ Important: Methods and properties of objects in VCL or CLX can only be
used
in a method called using Synchronize, for example,

Synchronize(UpdateCaption);

and UpdateCaption could look like,

procedure CDSQuery.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }

{ CDSQuery }

constructor TCDSQuery.Create(CreateSuspended: Boolean; CDS: TClientDataSet;
SQL: String);
begin
inherited Create(CreateSuspended);

FClientDataSet:= CDS;
FSQL:= SQL;

{ This will free the Thread once it has done its job }
FreeOnTerminate:= True;
end;

destructor TCDSQuery.Destroy;
begin
FClientDataSet:= Nil;

inherited Destroy;
end;

procedure TCDSQuery.DoQuery;
begin
{ Access to the FClientDataSet variable should only be in the Synchronize
protected area due to it being owned by another thread! }
if FClientDataSet.Active then
FClientDataSet.Close;

FClientDataSet.CommandText:= FSQL;

FClientDataSet.Open;
end;

procedure TCDSQuery.Execute;
begin
{ Place thread code here }
TRY
Synchronize(DoQuery);
EXCEPT
{ Make Silent Temporarily }
END;
end;

end.


I hope this was of help


Regards,


Scott Price


"Blackjack" <hua...@gxtorch.com.cn> wrote in message
news:3c020f87$1_2@dnews...

Manuel Parma

unread,
Nov 26, 2001, 11:29:37 PM11/26/01
to
Take a look to this example http://www.distribucon.com/midas/cdsthread.zip
your code maybe need look like this:
procedure TMyThread.Execute;
begin
OleCheck(CoInitialize(nil)); <- you need this
try
try
//at this point you need marshall the appserver interface into this
thread
//or open a new connection inside this thread!


Fclientdataset.CommandText:='select * from c_message';

Fclientdataset.Open; <- Here, an error occur: Raise exception class


Synchronize(StatusOut);
except
... do something here...
end;

finally
CoUninitialize;
end;
end;

Manuel Parma
mpa...@usa.net

"Blackjack" <hua...@gxtorch.com.cn> wrote in message
news:3c020f87$1_2@dnews...

Scott Price

unread,
Nov 27, 2001, 7:16:32 AM11/27/01
to
Hi Manuel,


It isn't just that simple unfortunately. The object reference
Fclientdataset is also pointing to an object that exists and was created in
a seperate thread. Obviously this would cause further concern.

Whilst you might - very fortunately - have been able to call the object
without issue up until that point, it would not have lasted for long, as
eventually the object would have caused its own exceptions due to this. The
only way to safely refer to that externally located object would be in a
synchronised block.

Whilst my appologies go out, you are indeed correct on the CoInitialize that
I forgot in my previous example - especially if refering to externally
supplied (other process) Providers.

All-in-all I hope all of this has helped Blackjack.


Regards,


Scott Price.

"Manuel Parma" <mpa...@usa.net> wrote in message news:3c03138d_1@dnews...

Alejandro Trotta

unread,
Nov 29, 2001, 8:56:54 AM11/29/01
to

Hi!,
About the example at http://www.distribucon.com/midas/cdsthread.zip
has any one rewrite for delphi 6?.

Thanks.
Alejandro Trotta.

Scott Price

unread,
Nov 29, 2001, 9:10:26 AM11/29/01
to
>> has any one rewrite for delphi 6?.

Sort-of,


I have created an example for Delphi 6.

I have mailed it to your email address,


Regards,


Scott Price.


0 new messages