Если ваша задача OTL должна загрузить отсортированный список компаний, которые соответствуют критериям:
// create and open query to fetch list of companies
while not qryCompanies.Eof do begin
C := TCompany.Create;
try
C.LoadFromDataset(qryCompanies);
Companies.Add(C);
except
C.Free;
raise;
end;
qryCompanies.Next;
end;
C
- ваш бизнес-объект для компании. Это может быть объект (TCompany
) или интерфейс (ICompany
), реализованный объектом. Companies
- это TList<TCompany>
или TList<ICompany>
. В конце задания вы отправляете список компаний в ветку VCL:
Task.Comm.Send(TOmniMessage.Create(MSGID_LIST_OF_COMPANIES, Companies));
В форме, в которой вы хотите отобразить список компаний, с которыми вы обрабатываете событие OnTaskMessage
экземпляра otlEventMonitor
, который отслеживает вашу задачу:
procedure TListBaseFrame.otlEventMonitorTaskMessage(
const task: IOmniTaskControl);
var
MsgID: word;
MsgValue: TOmniValue;
begin
task.Comm.Receive(MsgID, MsgValue);
Assert(MsgValue.IsInterface);
if fLoaderTask = task then begin
SetLoadedData(MsgID, MsgValue.AsInterface); // or MsgValue.AsObject);
fLoaderTask := nil;
end;
end;
Список компаний заменяет предыдущий список и может отображаться в сетке.
Аналогично, вы можете вернуть один объект / интерфейс компании для отображения и редактирования.
Две вещи, о которых стоит подумать:
Если вы до сих пор предпочитали объекты интерфейсам, написание многопоточных программ может быть причиной для пересмотра этого. Если вы создаете свои объекты в фоновом потоке, затем передаете их в поток VCL и забываете о них в фоновом потоке, тогда объекты могут работать хорошо. Однако я обнаружил, что гораздо лучшую производительность можно получить, кэшируя объекты в приложении и загружая только те записи из базы данных, которые еще не были загружены или изменились. Ко всем моим таблицам прикреплен индекс изменений (64-разрядное целое число, может также работать отметка времени), который изменяется при каждом обновлении. Вместо выполнения
select * from foo where (...) order by (...)
Я только когда-либо выполняю
select id, change_index from foo where (...) order by (...)
затем проверьте в кеше, существует ли объект с таким же идентификатором (первичным ключом) и индексом изменения, если это так, верните кешированный объект и только если не создайте новый бизнес-объект и загрузите все столбцы.
Но если вы кешируете объекты, у вас будут ссылки на них из нескольких потоков, и проблемы с владением вскоре станут настолько сложными, что управление временем жизни, основанное на подсчете ссылок, - единственный способ оставаться в здравом уме. Использование интерфейсов вместо объектов очень помогает в этом отношении.
Добавление объекта синхронизации к каждому бизнес-объекту необходимо, если несколько потоков могут обращаться к ним одновременно. Это, конечно, возможно, но может привести к дополнительной сложности и потенциальным тупикам. Если вы реализуете свои бизнес-объекты как неизменяемые, тогда блокировки вообще не нужны. Я использую этот подход все больше и больше, и хотя он требует некоторого привыкания, он может многое упростить.