You are not logged in.
How to read from database feeding a filtering list without memory leakage?
I have a windows-service that reads data from a table into a TObjectList
which is customized to filter out some data i.e. duplicate records.
That's because I couldn't find out how to do that with SQL and mORMot.
I have created a solution that works but I think it might be a
smarter solution.
Anyone that can tell?
Here is my solution:
Alt 1.
Alt 1. Just need one list and the finally is simpler.
procedure TEvNServer.readPkgPrefix(out aPrefixList: TPrefixList);
var
SQL: RawUTF8;
ppf: TSQLPkgPrefix;
newPkgPrefix: TSQLPkgPrefix;
begin
SQL := 'usedBySync = ? ORDER BY DefaultPrefix desc ';
ppf := TSQLPkgPrefix.CreateAndFillPrepare(fDBServer, SQL, [1]);
aPrefixList := TPrefixList.create;
try
while ppf.FillOne do begin
newPkgPrefix := TSQLPkgPrefix.create; // Clone object before adding to list
newPkgPrefix.assign(ppf); //
if aPrefixList.add(newPkgPrefix) = -1 then // if object not accepted by the list,
newPkgPrefix.free; // it must be free:d, otherwise mem-leakage
end;
finally
ppf.free; // must be free:d otherwise mem-leakage
end;
end;
Alt 2.
Alt 2. Dont need to clone and add the assign method to TSQLPkgPrefix class.
procedure TEvNServer.readPkgPrefix(out aPrefixList: TPrefixList);
var
SQL: RawUTF8;
ppf: TSQLPkgPrefix;
tmpList: TObjectList<TSQLPkgPrefix>;
begin
SQL := 'usedBySync = ? ORDER BY DefaultPrefix desc ';
tmpList := fDBServer.RetrieveList<TSQLPkgPrefix>(SQL, [1], '');
aPrefixList := TPrefixList.create;
try
for ppf in tmpList do begin
if aPrefixList.add(ppf) = -1 then begin
ppf.free;
end;
end;
finally
if assigned(tmpList) then begin
tmpList.OwnsObjects := false;
freeAndNil(tmpList);
end;
end;
end;
Last edited by larand54 (2021-07-07 09:53:39)
Delphi-11, WIN10
Offline
The FillOne version is faster since it will avoid some memory allocations.
So I am in favor of Alt 1.
Small optimization:
SQL := 'usedBySync = ? ORDER BY DefaultPrefix desc ';
aPrefixList := TPrefixList.create; // moved before to avoid a memory leak of ppf if the SQL is incorrect
ppf := TSQLPkgPrefix.CreateAndFillPrepare(fDBServer, SQL, [1]);
try
newPkgPrefix := TSQLPkgPrefix.create;
while ppf.FillOne(newPkgPrefix) do
if aPrefixList.add(newPkgPrefix) >= 0 then // if object accepted by the list,
newPkgPrefix := TSQLPkgPrefix.create; // it is owned by it -> need a new instance
newPkgPrefix.Free;
finally
ppf.Free;
end;
And I would not put aPrefixList as an "out" parameter, but as an input parameter, allocated by the caller - otherwise you may leak memory in case of exception.
Offline
Thanks, that was much better - I've already tested and it works perfectly!
Delphi-11, WIN10
Offline