Еще один короткий пост-шпаргалка. Те, кто использует FastReport должны знать, что организация многоуровневых отчетов главный-подчиненный производится, если так можно выразиться, естественным образом. Т.е. для создания такого отчета нужно связать исходные источники данных связью Master-Details. Официальная документация FastReport весьма подробно рассказывает как это сделать.
Проблема заключается в том, что у некоторых DataSet‘ов, в частности у TADOQuery, отсутствуют свойства MasterSource и MasterField. Это отнюдь не означает, что с помощью этих компонентов нельзя построить отчет с несколькими уровнями данных. Однако, для этого необходимо организовать связь Главный-Подчиненный вручную. Вариантов того, как это сделать достаточно много. Один из простейших – обработать событие OnAfterScroll для главного датасета. Например, так:
qryExpenses.Close;
qryExpenses.Parameters.ParamByName(‘EXPCATEGORY_ID’).Value:= qryCategoriesExpCategoryID.AsInteger;
qryExpenses.Open;
Данный вариант вполне устроил FastReport.
Пользуясь случаем напоминаю, что для зарегистрированных пользователей Delphi XE3 FastReport FMX Embarcadero Edition доступна. Владельцы Delphi XE3 могут использовать данную редакцию продукта бесплатно.
Полная однопользовательская версия FastReport FMX продукта стоит 7999 руб.
как же это не оптимально, делать n-однородных запросов к БД…
Ага. Я ожидал этот комментарий. И как же оптимально?
Александр, попробуйте использовать свойства Filter и Filtered. В TADOQuery они точно есть, правда я не помню деталей, но вроде этот фильтр локальный, т.е. при его включении не происходит запроса к БД.
Естественно, я попробовал это сделать
и не получилось?
а вызвать First после Filtered := True?
На самом деле, в данной ситуации, как мне кажется, можно использовать ClientDataSet. Что бы один раз загрузить набор данных и там “его танцевать” с помощью Master-Detail. Обязательно, на досуге сравню производительность.
вычитал в справке, что если CursorLocation = clUseClient (значение по дефолту), то фильтр применяется локально. Если CursorLocation = clUseServer – то текст фильтра тупо примешивается к Where условию запроса.
Т.е. набор в этом случае переоткрывается?
Вообще еще огромный вопрос как реализован в каждом конкретном датасете мастер-детейл, там, где он есть.
И еще очень хочется посмотреть, а что же там в AnyDAc по этому поводу. Но это только завтра.
Нет. Если фильтр локальный – то данные фильтруются на клиенте, НД _не_ переоткрывается.
Т.е. примерно как-то так
qryExpenses.Open; -> выполнили запрос к БД один раз
...
OnAfterScroll:
qryExpenses.Filter := 'EXPCATEGORY_ID=' + qryCategoriesExpCategoryID.AsString;
qryExpenses.Filtered := True;
qryExpenses.First;
интересная вещь:
http://www.fast-report.com/public_download/html/UserMan-ru/tfrxadoquery.htm
Т.е. то, что Вы сделали в скрипте (в рантайме), можно сделать через свойства в дизайнтайме.
Можно. Я знаю эту вещь. Только не в Base редакции. Вероятно, из этих соображений оно и добавлено.
как эксперименты по производительности? удалось провести?
Николай, я обязательно проведу и напишу об этом. Как раз и база подходящая нарисовалась с реальными данными. Но чуть позже. Сегодня у меня FireDAC.