Solved

Writing a Message/Record Log

Posted on 2001-06-14
11
238 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
 
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
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
This Micro Tutorial demonstrates using Microsoft Excel pivot tables, how to reverse engineer competitors' marketing strategies through backlinks.
Many functions in Excel can make decisions. The most simple of these is the IF function: it returns a value depending on whether a condition you describe is true or false. Once you get the hang of using the IF function, you will find it easier to us…

920 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