Page 1 of 1

[patch_done] Bug in Master/Detail Mechanisms

Posted: 04.02.2011, 13:40
by scheurer
unit ZAbstractRODataset;
...
TZDataLink = class(TDataLink)
...

is not correct for MD Relations, since it breaks Delphi Code for
enumerating Detaildatasets. Try dataset.getdetaildatasets(tlist) and
the answer is 0 Detaildatasets.

Bug is fixed with
...
TZDataLink = class(TMasterDataLink)
...

and
...
constructor TZDataLink.Create(ADataset: TZAbstractRODataset);
begin
inherited Create(ADataset);
FDataset := ADataset;
end;
...

Missing features:
doonnewrecord is incomplete for serversided MD Relations

The following code do the trick

...
procedure TZAbstractRODataset.DoOnNewRecord;
...
begin
if MasterLink.Active and (MasterLink.Fields.Count > 0) then begin
...
end else begin
if DataLink.Active and (DataLink.dataset.Fields.Count > 0) then begin
p1 := 1; p2 := 1;
while (P1 <= Length(LinkedFields)) and (p2 <= Length(MasterFields))
do begin
DetailField := FieldByName(ExtractFieldName(LinkedFields, P1));
MasterField := DataLink.DataSet.FieldByName
(ExtractFieldName(MasterFields, P2));
DetailField.Assign(MasterField);
end;
end;
end;
end;
...

With linkedfields=Lfield1;lfield2,lfield3...
and MasterFields=Mfield1;mfield2;Mfield3...
the content of the Masterfield is copied into the corresponding
likedfield.

Cascading delete
With a working getdetailrecordsets the following code seems to work

...
procedure TZAbstractDataset.InternalDelete;
var
RowNo: Integer;
RowBuffer: PZRowBuffer;
i: Integer;
Detailsets: TList;
ds: TZAbstractDataset;
begin
Detailsets := TList.create;
getdetaildatasets(Detailsets);
for i := 0 to Detailsets.Count - 1 do begin
ds := TZAbstractDataset(Detailsets);
with ds do begin
if not Active then Open;
first;
while not Eof do begin
Delete;
end;
end;
end;
Detailsets.Free;
...
end;
...

Hope this additions are usefull

Karl Scheurer

Posted: 02.04.2011, 21:45
by mdaems
Karl,

I was able to add first 2 changes without problems (=didn't break test suite).
The InternalDelete can only be added for Delphi. FPC doesn't support it. (In case you know how to do it : feel free to send the fix ;) )

These changes have been applied to SVN testing branch revision 881 yesterday.

Mark

Posted: 12.04.2011, 13:39
by trupka
mdaems,
this patch is VERY DANGEROUS and can cause data loss. Specifically

Code: Select all

...
procedure TZAbstractDataset.InternalDelete;
var
RowNo: Integer;
RowBuffer: PZRowBuffer;
i: Integer;
Detailsets: TList;
ds: TZAbstractDataset;
begin
Detailsets := TList.create;
getdetaildatasets(Detailsets);
for i := 0 to Detailsets.Count - 1 do begin
ds := TZAbstractDataset(Detailsets[i]);
with ds do begin
if not Active then Open;
first;
while not Eof do begin
Delete;
end;
end;
end;
Detailsets.Free;
It deletes everything from detail datasets without confirmation (cascade delete)
* database foreign keys wont constrain this in case you have linked detail dataset, even inactive
* this is opposite behaviour then other delphi database components (ibx, bde and similar) where you first must delete data from detail sets "manually". Developers won't expect this auto-delete feature.
* with few strategically positioned master-detail queries it's possible to empty entire database
* we already have cascade-delete mechanisms if needed - with tzupdatasql and/or database level triggers, constraits etc.. or inside delphi code.
* we all make mistakes - if app raises exception that can't delete something it should, this can be fixed. If it deletes something it shouldn't, only backup can help. Maybe...

So, IMO, this should be removed from ZEOS.

Posted: 19.05.2011, 21:37
by mdaems
trupka,

I removed the cascading delete part of this patch in SVN rev. 902.

Mark