Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

Writing a Message/Record Log

Posted on 2001-06-14
11
242 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
Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
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

Networking for the Cloud Era

Join Microsoft and Riverbed for a discussion and demonstration of enhancements to SteelConnect:
-One-click orchestration and cloud connectivity in Azure environments
-Tight integration of SD-WAN and WAN optimization capabilities
-Scalability and resiliency equal to a data center

Question has a verified solution.

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

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
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…
This video shows how to use Hyena, from SystemTools Software, to bulk import 100 user accounts from an external text file. View in 1080p for best video quality.
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

809 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