Solved

Writing a Message/Record Log

Posted on 2001-06-14
11
235 Views
Last Modified: 2010-04-06
I am writing an app and the user has requested that a LOG file be kept that shows ALL modifications made to each table. ie. Date, time, who made the change, table modified, actual data before change, data after modification, type of modification.

As there are approximately 20-30 tables that would need to be tracked, I thought that when a table is modified, I could call a single function which updated a LOG Table.

My question, where would be the best place to call the function or functions, ie. BeforeEdit, AfterEdit, OnUpdateRecord etc.

I understand that I would possibly have to call the function before and after updates to record previous data and new data.

Also, would I have to call this function from every table I modify, or is there a single place I could call it from.
0
Comment
Question by:pjelias
11 Comments
 
LVL 1

Expert Comment

by:Greyman
Comment Utility
I assume from your question that you are using TTable objects.

The easiest way to implement this would be to write a BeforePost handler to dump the change details of records that are being changed or added, and an AfterPost handler to confirm that the changed record was written successfully.

For deletions, you'll need to do the same sort of thing, using BeforeDelete and AfterDelete.

Note that you can get the previous value for a field using OldValue - you should also look into accessing the TField objects by number instead of name (this will allow you to use the same event handler on each table).

To implement this approach, you would need to hook up every table to the event handlers that you write (you should be able to reuse handlers, however).  You could do that using a custom component if you are comfortable with component writing, but I would avoid biting off more than I could chew ;)
0
 
LVL 2

Expert Comment

by:Felixin
Comment Utility
Are you using sql?

The use of trigger will make your application easier.
0
 

Author Comment

by:pjelias
Comment Utility
I am using Paradox tables with TTables (and wwTables - Infopower equivalent)
0
 
LVL 9

Expert Comment

by:ITugay
Comment Utility
Hi pjelias,

Easy way to solve you problem is to create your own TTable component derived from standard TTable. You can place all logic there (override DoBeforePost methods and so on). Then you need to replace all TTable in your project to your new TTable component.  Does it look like OOP? :-)

-----
Igor.

0
 
LVL 3

Expert Comment

by:nnbbb09
Comment Utility
Note that the OldValue property only works if you have CachedUpdates set to true
0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 
LVL 1

Expert Comment

by:Moondancer
Comment Utility
Is this the question you posted questions about in the Community Support Topic area?

Moondancer
Community Support Moderator @ Experts Exchange
0
 

Author Comment

by:pjelias
Comment Utility
ITugay,

could you please explain further, or provide an example
0
 
LVL 1

Expert Comment

by:Greyman
Comment Utility
Please note that ITugay's suggestion was covered in my suggestion:

"You could do that using a custom component if you
are comfortable with component writing, but I would avoid biting off more than I could chew ;) "

0
 

Author Comment

by:pjelias
Comment Utility
Sorry Greyman, I thought ITugay was talking about something else, didn't read comment fully.

I thought what you suggested would be the case, so I have tried to write code accordingly.

My problem is the following, what I want to be able to do is get the field names and values for the current record before edit, delete etc. and insert these into a Memo Field within my event log table.

I have got the theory and code basically working for a single table, the problem is trying to do this so that I can call the procedure/function from any table/dataset, by passing a few parameters, rather than attaching the same code to every table.

For example. If I have the following TTables, TableA, TableB, TableC and TableLOG, where TableLOG is the event LOG File with the following fields/types

DateTime  DateTime
UserID    Alphanumeric
TableName Alphanumeric
OldData   Memo

What I want to do is get the Field Contents of the Current Record for the current Table, which I add to a StringList and then insert in the EventLog OldData Memo field.
0
 
LVL 1

Accepted Solution

by:
Greyman earned 100 total points
Comment Utility
Try this snippet:


var
  TempStrings : TStrings;
  Counter : integer;
begin
  TempStrings := TStringList.Create;
  try
    for Counter := 0 to DataSet.FieldCount - 1 do begin
      TempStrings.Add(DataSet.Fields[Counter].Name + '=' + DataSet.Fields[Counter].AsString);
    end;
    OldData := TempStrings;  // This only works if OldData is a TMemoField.
    OldData.AsString := TempStrings.CommaText;  //This will work for any char field.
  finally
    TempStrings.Free;
  end;
end;

Note that this is code for a TDataSetNotifyEvent - (such as BeforePost) these events take a parameter DataSet of type TDataSet.

I haven't handled null values in a sophisticated way, but I figure you can add that extension yourself.

HTH



Nick
0
 

Author Comment

by:pjelias
Comment Utility
Greyman,

thanks for that, but I actually worked it out before I read your response, see my code below


procedure TdMod.t2BeforeEdit(DataSet: TDataSet);
begin
  tName:=t2.TableName;
  GetData(DataSet,tName,'EDIT');
end;

procedure TdMod.t2BeforeDelete(DataSet: TDataSet);
begin
  tName:=t2.TableName;
  GetData(DataSet,tName,'DELETE');
end;

procedure TdMod.GetData(dSet: TDataSet; vTable,vType: String);
var sList: TStringList;
    fName,fVal,tName: String;
    fVar: Variant;
    i: Integer;
begin
  sList:=TStringList.Create;
  for i := 0 to dSet.FieldCount-1 do
  begin
    fName:=dSet.Fields[i].Name;
    if dSet.fields[i].IsIndexField then fName:=fName+'*';
    fVal:=dSet.Fields[i].AsString;
    sList.Add(fName+':= '+fVal);
  end;
  if not tLog.Active then tLog.Active:=True;
  tLog.InsertRecord([now,'userid',vTable,vType,sList]);
  sList.Free;
end;

Will give you the points anyway.

Thanks again
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

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 Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
This video discusses moving either the default database or any database to a new volume.

744 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

16 Experts available now in Live!

Get 1:1 Help Now