Hi Terry

This is the solution I came up with:

1/. Use ClientDataSets.  Keep your queries, but have a Provider (D4) or
DataSetProvider (D5) and ClientDataSet for each, and attach your data-aware
controls to the ClientDataSet instead.  You may want to move your calculated
fields to the ClientDataSet, but you can keep them where they are and
specify them as InternalCalc - this will complicate things later however
(discussed below).

2/. After committing any data change, broadcast a message to all open forms
indicating that data has changed along with specifics of the table, and
ideally the changes to the data as well (this will save each form that
receives the message from having to execute a query to see the new data).

3/. Have your data-aware forms (except the one that sent the message)
receive and respond to this message, and if necessary update their
ClientDataSets to reflect the change.  The way I did this was to go have a
procedure to replace the BeforeUpdateRecord of the Provider, as follows:

procedure TForm1.NULLBeforeUpdateRecord(Sender: TObject;
  SourceDS: TDataSet; DeltaDS: TClientDataSet; UpdateKind: TUpdateKind;
  var Applied: Boolean);
begin
  Applied := True; // No database updates need to be made
end;

Then your code will be:

procedure TForm1.RespondToMyMessage(var MyMessage: TMyMessage);
begin
  // Check if ClientDataSet1 needs updating - with a bit of work you can
write this generically
  ...
  LBookmark := ClientDataSet1.GetBookmark;
  try
    // Find the record you need to update in ClientDataSet1, if any, using
the key in MyMessage.  Note that MyMessage needs to contain the old key
fields as well, if the key or part of the key has changed.
    if ClientDataSet1.Locate(...) then begin
      ClientDataSet1.Edit;
      // Update ClientDataSet1 with all the fields that have changed, using
the data in MyMessage.  This assumes you haven't any unapplied edits in
ClientDataSet1!  Incidently, this is where things get complicated if you had
InternalCalc fields, as they will NOT be updated when the data they are
based on is updated, so you have to somehow recalculate them now.
      ...
      ClientDataSet1.Post;
      LBeforeUpdateRecord := Provider1.BeforeUpdateRecord;
      Provider1.BeforeUpdateRecord := NULLBeforeUpdateRecord; //
Automatically apply updates
      try
        ClientDataSet1.ApplyUpdates;
      finally
        Provider1.BeforeUpdateRecord := LBeforeUpdateRecord;
      end;
      ClientDataSet1.GotoBookmark(LBookmark);
    end;
  finally
    ClientDataSet1.FreeBookmark(LBookmark);
  end;
end;

There's more - you need to faff around even more if you happen to be
updating the ClientDataSet at the time you receive the message.

So anyway, that's my solution.  If you try it, let me know how you get on.
It does take a fair bit of effort to get it all working smoothly.  I would
say that it's worth the investment of time for a large application, but I
can't help but feel it shouldn't have to be this much work.  If there isn't
a better solution (and I welcome any suggestions) then you'd have to say
that Delphi doesn't handle this issue particularly well, which is
disappointing given how fundamental an issue it is.

Maybe you're meant to just close your application and restart it every time
you update your data?  :)

Cheers,
Carl

> -----Original Message-----
> From: Terry Johnson [mailto:[EMAIL PROTECTED]]
> Sent: Friday, 10 December 1999 0:06
> To: Multiple recipients of list delphi
> Subject: [DUG]: Mixing tables and queries
> 
> 
> Suppose you have a TQuery running on a transaction-ish 
> database. You can
> select ranges of dates, customers et al happily, and are 
> reluctant to do it
> with anything other than SQL. By setting 'request live' true, 
> you can even
> edit (table) data directly in a grid.
> 
> However, should you also need to be able to access data via, say,
> transaction number directly (such as for a 'find transaction' kind of
> function) where you can also edit the underlying database, 
> without closing
> the DBGrid view of the data (i.e. in a separate window), you 
> wind up with
> different versions of the same record in different windows.
> 
> So, how can you update the Query so that the fields change to 
> reflect the
> changing database without having to rerun the query and 
> search sequentially
> through the table to find the record you were on (cursor 
> location) before
> you re-ran the query?
> 
> This is a problem I've been trying to find a nice tidy 
> solution to for some
> time, and I would very much like to know what options are available. 
> 
> Cheers,
> Terry
> --------------------------------------------------------------
> -------------
>     New Zealand Delphi Users group - Delphi List - 
> [EMAIL PROTECTED]
>                   Website: http://www.delphi.org.nz
> 

---------------------------------------------------------------------------
    New Zealand Delphi Users group - Delphi List - [EMAIL PROTECTED]
                  Website: http://www.delphi.org.nz

Reply via email to