Roman Wilk

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 ?

konto usunięte

Temat: Delphi 2010, ClientDataSet i pola Blob

Nie znam Delphi 2010, ale sprawdź czy ta linijka:
BlobFileName: array [0 .. 10] of string[100];

nie deklaruje czasami shortstring.

Bo jeśli tak, to masz tam konwersję w pętli (w kilku miejscach).
Żeby to zweryfikować pewnie wystarczy coś takiego:
http://stackoverflow.com/questions/554100/how-to-know-...

Btw. Powinno się to nazywać chyba BlobFieldName.Piotr L. edytował(a) ten post dnia 09.01.12 o godzinie 00:16



Wyślij zaproszenie do