Roman
Wilk
Tak właściwie, to
gram dużo w squash'a
:), ale to wciąż
z...
Temat: Delphi 2010, ClientDataSet i pola Blob
Witam,Używam ClientDataSet'a np. do tworzenia / edycji praktycznie wszystkich konstrukcji typu Master / Details (np. tworzenie pozycji dokumentu FV, WZ itd). Kod w D7, który poniżej zamieszczam kopiował (rekord po rekordzie, bo tak ma być) zawartość zapytania zawartego w IBQuery w ciągu maxymalnie kilku sekund (np. dla 1000 pozycji dokumentu trwało to 3s).
function CopyDetailTable(localTable: TClientDataSet; detailTable:
TIBTable; masterTable: TIBTable;
indexMasterValue: Variant; EmptyBefore: Boolean = True): Integer; var
i: Integer;
IBQuery1: TIBQuery;
FieldName: string;
procedure CopyRecord(localTable: TClientDataSet; query: TIBQuery); var
i: Integer;
FieldName: string;
begin
if not query.Active then
query.Open;
TableState(localTable);
localTable.Append;
for i := 0 to localTable.FieldCount - 1 do
begin
try
FieldName := localTable.Fields[i].FieldName;
if query.FieldList.Find(FieldName) = nil then
continue;
if localTable.FieldByName(FieldName).FieldKind = fkData then
localTable.FieldByName(FieldName).Value := query.FieldValues[FieldName];
except
end;
end;
localTable.Post;
end;
begin
IBQuery1 := TIBQuery.Create(Application);
IBQuery1.Database := IBDLOG.IBDBKameleon;
try
localTable.DisableControls;
if EmptyBefore then
while not localTable.IsEmpty do
localTable.Delete;
Result := 0;
TableState(localTable);
if not ExistsRecord(detailTable.MasterFields,
masterTable.tableName, indexMasterValue) then
exit;
with IBQuery1 do
begin
Close;
SQL.Add(Format('SELECT * FROM %s WHERE %s = :index', [detailTable.tableName, detailTable.indexFieldNames]));
ParamByName('index').Value := indexMasterValue;
Open;
end;
IBQuery1.First;
while not IBQuery1.Eof do
begin
CopyRecord(localTable, IBQuery1);
IBQuery1.Next;
end;
Result := localTable.RecordCount;
finally
localTable.EnableControls;
IBQuery1.Free;
IBQuery1 := nil;
end;
end;
Ten sam kod w D2010 robi to w ciągu 20 s !!!??? (czym to tłumaczyć, Unicode ? Przecież IBQuery wszystkie stringi już zwraca jako WideString, a w ClintDataSet są one zadeklarowane jako WideString), poza tym ClientDataSet tworzy dynamicznie strukturę pól na podstawie wzorca z TIBTable).
Ponieważ wydajność powyższego rozwiązania w kodzie wygenerowanym D2010 jest nie do przyjęcia. Zastąpiłem powyższe poniższym
procedure CopyRecords(DataSet: TClientDataSet;IBQuery: TIBQuery;
indexValue: Variant);
var
tmp: TDataSetProvider;
data: OleVariant;
i: Integer;
BlobFileCount: Integer;
BlobFileName: array [0 .. 10] of string[100];
function IsBlobFiledsExist: Boolean;
var
i, j: Integer;
begin
for i := 0 to 10 do
BlobFileName[i] := '';
Result := false;
j := 0;
for i := 0 to IBQuery.FieldCount - 1 do
if IBQuery.Fields[i].DataType in [ftBlob,ftFmtMemo, ftMemo] then
begin
Result := True;
BlobFileName[j] := IBQuery.Fields[i].FieldName;
Inc(j);
end;
end;
function GetBlobFileCount: Integer;
var
i: Integer;
begin
Result := 0;
for i := 0 to 10 do
if BlobFileName[i] <> '' then
Result := i;
end;
function IsBlobValueExist(Field: TField): Boolean;
begin
Result := (not Field.IsNull) and (Field.AsString <> '');
end;
procedure CheckBlobFields;
var
i: Integer;
begin
if IsBlobFiledsExist then
begin
BlobFileCount := GetBlobFileCount;
IBQuery.First;
while not IBQuery.Eof do
begin
for i := 0 to BlobFileCount do
if IsBlobValueExist(IBQuery.FieldByName(BlobFileName[i]))
then
if
DataSet.Locate(indexValue,IBQuery.FieldByName(indexValue).AsVariant,
[]) then
begin
DataSet.Edit;
DataSet.FieldByName(BlobFileName[i]).Value := IBQuery.FieldByName(BlobFileName[i]).Value;
DataSet.Post;
end;
IBQuery.Next;
end;
end;
end;
begin
try
tmp := TDataSetProvider.Create(nil);
tmp.DataSet := IBQuery;
DataSet.data := tmp.data;
CheckBlobFields;
finally
tmp.Free;
end;
end;
Ale jak widać z powyższego kodu, muszę sprawdzać czy w polach są blob'y i ponownie je przepisać ponieważ samo :
tmp.DataSet := IBQuery;
DataSet.data := tmp.data;
niestety kopiuje tylko 1 znak z pola typu Blob
Na ClientDataSet są ustawione wszystkie potrzebne flagi np.
FetchOnDemand =:true
Czy ktoś ma może jakiś pomysł, jak zmusić taką konstrukcję do kopiowania całej zawartości pól typu Blob ?