为我们的数据库应用程序编写一些更改日志,我面临以下问题:在我的DataSetProvider的BeforeUpdateRecord事件中,缺少任何(已修改的)WideMemo字段的OldValue。
很明显,它在我ApplyUpdates之前就存在于ClientDataSet中,因此在创建增量或由DataSetProvider对其进行解压缩时,它会被丢弃。
如何获得该价值?
只是在相关的情况下,这是我使用的组件
客户端: TClientDataSet TDataSource
服务器端: TIB查询 TDataSetProvider
连接到Firebird数据库
Delphi Tokyo和Datasnap
干杯!
答案 0 :(得分:1)
我想我会将其发布为新答案,作为对我现在所理解的新答案
从OP的评论中可以看出他的具体问题。 OP想要做的是捕获数据集字段的OldValue
服务器端,即IBQuery,而不是TDatasetProvider的客户端。一旦确定OP已经看到这个答案,我将把我以前的答案记下来。
考虑以下代码:
type
TMyIBQuery = Class(TIBQuery)
end;
procedure TForm1.IBQuery1BeforePost(DataSet: TDataSet);
var
OldValue : Variant;
PrvState : TDataSetState;
begin
PrvState := IBQuery1.State;
try
TMyIBQuery(IBQuery1).SetTempState(dsOldValue);
OldValue := IBQuery1.FieldByName('AValue').OldValue;
Memo1.Lines.Add('OldValue: ' + OldValue);
finally
TMyIBQuery(IBQuery1).RestoreState(PrvState);
end;
end;
如果DataSetProvider具有默认设置,则在以下情况下不调用IBQuery1BeforePost
在连接到DSP的CDS上调用ApplyUpdates
,因为应用过程
更新会绕过正常的IBQuery编辑过程。
但是,如果将DSP的ResolveToDataSet
属性设置为True
,则IBQuery1BeforePost
是否执行并正确提取AValue
字段的OldValue,它是WideMemo
我的设置中的字段。当然,执行AfterPost代码的原因是当ResolveToDataSet时
设置为True,则使用通常的IBQuery编辑方法。
更新:以下是我在评论中提到的项目摘录:
代码提取
type
TForm1 = class(TForm)
DataSource1: TDataSource;
DBGrid1: TDBGrid;
DBNavigator1: TDBNavigator;
IBDatabase1: TIBDatabase;
IBTransaction1: TIBTransaction;
Memo1: TMemo;
IBEvents1: TIBEvents;
IBQuery1: TIBQuery;
IBUpdateSQL1: TIBUpdateSQL;
LblTrans: TLabel;
Timer1: TTimer;
IBQuery1ID: TIntegerField;
IBQuery1ANAME: TIBStringField;
IBQuery1AVALUE: TWideMemoField;
DBMemo1: TDBMemo;
DataSetProvider1: TDataSetProvider;
CDS1: TClientDataSet;
[...]
end;
[...]
procedure TForm1.FormDestroy(Sender: TObject);
begin
IBQuery1.Close;
if IBTransaction1.InTransaction then
IBTransaction1.Commit;
if IBTransaction1.Active then
IBTransaction1.Active := False;
if IBEvents1.Registered then
IBEvents1.Registered := False;
IBDatabase1.Connected := False;
end;
procedure TForm1.RefreshTable2;
begin
if IBQuery1.Modified then
IBDatabase1.ApplyUpdates([IBQuery1]);
RefreshDS;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
UpdateTransLabel;
end;
procedure TForm1.UpdateTransLabel;
begin
if IBTransaction1.Active then
lblTrans.Caption := 'Trans Active'
else
lblTrans.Caption := 'Trans Inactive';
end;
procedure TForm1.CDS1AfterPost(DataSet: TDataSet);
begin
CDS1.ApplyUpdates(0);
end;
procedure TForm1.DBNavigator1BeforeAction(Sender: TObject; Button:
TNavigateBtn);
begin
if IBQuery1.CanModify then
lblTrans.Caption := lblTrans.Caption + ' RW'
else
lblTrans.Caption := lblTrans.Caption + ' RO'
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Caption := ExtractFileName(Application.ExeName) + ' / ' + IBDatabase1.Params.Values['user_name'];
IBQuery1.Open;
end;
procedure TForm1.IBDatabase1AfterConnect(Sender: TObject);
begin
IBDatabase1.Connected := True;
IBEvents1.Registered := True;
end;
procedure TForm1.IBEvents1EventAlert(Sender: TObject; EventName: string;
EventCount: Integer; var CancelAlerts: Boolean);
begin
Memo1.Lines.Add('Evt: (' + IntToStr(EventCount) + ') ' + EventName);
end;
procedure TForm1.CommitAndRefresh;
begin
IBTransaction1.CommitRetaining;
RefreshTable2;
end;
procedure TForm1.IBQuery1AfterDelete(DataSet: TDataSet);
begin
CommitAndRefresh;
end;
procedure TForm1.IBQuery1AfterPost(DataSet: TDataSet);
begin
CommitAndRefresh;
end;
type
TMyIBQuery = Class(TIBQuery)
end;
procedure TForm1.IBQuery1BeforePost(DataSet: TDataSet);
var
OldValue : Variant;
PrvState : TDataSetState;
begin
PrvState := IBQuery1.State;
try
TMyIBQuery(IBQuery1).SetTempState(dsOldValue);
OldValue := IBQuery1.FieldByName('AValue').OldValue;
Memo1.Lines.Add('OldValue: ' + OldValue);
finally
TMyIBQuery(IBQuery1).RestoreState(PrvState);
end;
end;
procedure TForm1.IBQuery1UpdateError(DataSet: TDataSet; E: EDatabaseError;
UpdateKind: TUpdateKind; var UpdateAction: TIBUpdateAction);
begin
UpdateAction := UpdateErrorForm.HandleError(DataSet, E, UpdateKind);
end;
procedure TForm1.RefreshDS;
var
BM : TBookmark;
begin
BM := IBQuery1.GetBookmark;
try
IBQuery1.Close;
IBQuery1.Open;
finally
if IBQuery1.BookmarkValid(BM) then
IBQuery1.GotoBookmark((BM));
IBQuery1.FreeBookmark(BM);
end;
end;
end.
DFM提取
object Form1: TForm1
[...]
object LblTrans: TLabel
[...]
Alignment = taRightJustify
Caption = '???'
end
object DBGrid1: TDBGrid
[...]
DataSource = DataSource1
Columns = <
item
Expanded = False
FieldName = 'ID'
Visible = True
end
item
Expanded = False
FieldName = 'ANAME'
Width = 80
Visible = True
end
item
Expanded = False
FieldName = 'AVALUE'
Width = 200
Visible = True
end>
end
object DBNavigator1: TDBNavigator
[...]
DataSource = DataSource1
end
object Memo1: TMemo
[...]
end
object DBMemo1: TDBMemo
[...]
DataField = 'AVALUE'
DataSource = DataSource1
end
object DataSource1: TDataSource
DataSet = CDS1
end
object IBDatabase1: TIBDatabase
Connected = True
DatabaseName = 'LocalHost:D:\Delphi\Interbase\Databases\MA.GDB'
Params.Strings = (
'user_name=SYSDBA'
'password=masterkey')
LoginPrompt = False
DefaultTransaction = IBTransaction1
ServerType = 'IBServer'
TraceFlags = [tfQPrepare, tfQExecute, tfQFetch, tfError, tfStmt, tfConnect, tfTransact, tfBlob, tfService, tfMisc]
AfterConnect = IBDatabase1AfterConnect
end
object IBTransaction1: TIBTransaction
Active = True
DefaultDatabase = IBDatabase1
DefaultAction = TACommitRetaining
Params.Strings = (
'read_committed'
'rec_version'
'nowait')
end
object IBEvents1: TIBEvents
AutoRegister = False
Database = IBDatabase1
Events.Strings = (
'NewRow'
'RowDeleted'
'RowUpdated')
Registered = False
OnEventAlert = IBEvents1EventAlert
end
object IBQuery1: TIBQuery
Database = IBDatabase1
Transaction = IBTransaction1
AfterDelete = IBQuery1AfterDelete
AfterPost = IBQuery1AfterPost
BeforePost = IBQuery1BeforePost
BufferChunks = 1000
CachedUpdates = False
ParamCheck = True
SQL.Strings = (
'select * from table2')
UpdateObject = IBUpdateSQL1
Left = 112
FieldName = 'ID'
Origin = '"TABLE2"."ID"'
ProviderFlags = [pfInUpdate, pfInWhere, pfInKey]
end
object IBQuery1ANAME: TIBStringField
FieldName = 'ANAME'
Origin = '"TABLE2"."ANAME"'
Size = 80
end
object IBQuery1AVALUE: TWideMemoField
FieldName = 'AVALUE'
Origin = '"TABLE2"."AVALUE"'
ProviderFlags = [pfInUpdate]
BlobType = ftWideMemo
Size = 8
end
end
object IBUpdateSQL1: TIBUpdateSQL
RefreshSQL.Strings = (
'Select '
'from table2 '
'where'
' ID = :ID')
ModifySQL.Strings = (
'update table2'
'set'
' ID = :ID,'
' ANAME = :ANAME,'
' AVALUE = :AVALUE'
'where'
' ID = :OLD_ID')
InsertSQL.Strings = (
'insert into table2'
' (ID, ANAME, AVALUE)'
'values'
' (:ID, :ANAME, :AVALUE)')
DeleteSQL.Strings = (
'delete from table2'
'where'
' ID = :OLD_ID')
end
object Timer1: TTimer
OnTimer = Timer1Timer
end
object DataSetProvider1: TDataSetProvider
DataSet = IBQuery1
ResolveToDataSet = True
end
object CDS1: TClientDataSet
Active = True
Aggregates = <>
Params = <>
ProviderName = 'DataSetProvider1'
AfterPost = CDS1AfterPost
end
end
表DDL
CREATE TABLE "TABLE2"
(
"ID" INTEGER NOT NULL,
"ANAME" VARCHAR(80),
"AVALUE" BLOB SUB_TYPE TEXT SEGMENT SIZE 80
);
CREATE TRIGGER "GETTABLE2ID" FOR "TABLE2"
ACTIVE BEFORE INSERT POSITION 0
AS
begin
new.ID = gen_id("TABLE2ID", 1);
POST_EVENT('NewRow');
end
CREATE TRIGGER "UPDATETABLE2ROW" FOR "TABLE2"
ACTIVE AFTER UPDATE POSITION 0
AS
begin
POST_EVENT('T2 RowUpdated');
end
COMMIT WORK