Solved

Writing a Message/Record Log

Posted on 2001-06-14
11
241 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
ID: 6194024
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
ID: 6194177
Are you using sql?

The use of trigger will make your application easier.
0
 

Author Comment

by:pjelias
ID: 6194193
I am using Paradox tables with TTables (and wwTables - Infopower equivalent)
0
Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

 
LVL 9

Expert Comment

by:ITugay
ID: 6194952
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
ID: 6196827
Note that the OldValue property only works if you have CachedUpdates set to true
0
 
LVL 1

Expert Comment

by:Moondancer
ID: 6215719
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
ID: 6216625
ITugay,

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

Expert Comment

by:Greyman
ID: 6216654
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
ID: 6226612
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
ID: 6226623
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
ID: 6226804
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

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

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

Suggested Solutions

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
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 tutorial gives a high-level tour of the interface of Marketo (a marketing automation tool to help businesses track and engage prospective customers and drive them to purchase). You will see the main areas including Marketing Activities, Design …
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…

816 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

12 Experts available now in Live!

Get 1:1 Help Now