Участник
Регистрация: 28.11.2005
Адрес: Москва
|
Цитата:
Сообщение от Gustav
А можно и буфер не напрягать, и в экселе одну-единственную команду для вставки использовать, т.е. одним махом вставить весь ваш предварительно подготовленный в памяти массив данных - несколько столбцов и несколько тысяч строк.
Да, CopyFromRecordset - чумовая вещь Единственное, с чем лично я столкнулся в использовании ADODB.Recordset, - это работа в 3-хуровневой конфигурации, когда данные для отчета (и сам Recordset) формируются, как и положено, на сервере, а выводятся в Excel на клиенте. В этом случае необходимо организовать передачу данных на клиента и формировать Recordset там, что я реализовал через небольшой вспомогательный класс. Структура Recordset передается в виде запакованного массива контейнеров [название_поля, тип_поля_ADO], а данные - в виде запакованного Map (номер строки->контейнер данных). Для передачи структуры Recordset Map не подходит - названия колонок отсортируются по алфавиту Выглядит работа примерно так: X++: #define.ReportTemplateName ('ReportTemplate.xlt')
// нзвания полей - заголовков табличной части шаблона и названия колонок в RecordSet
#define.fldAccountNum ('AccountNum')
#define.fldTransDate ('TransDate')
#define.fldDocumentDesc ('DocumentDesc')
#define.fldAmount ('LineAmount')
// названия полей в шапке шаблона
#define.fldHdrLine1 ('headerLine1')
#define.fldHdrLine2 ('headerLine2')
#define.fldHdrLine3 ('headerLine3')
// название ячейки, откуда будет начат вывод строк
#define.fldReportLines ('reportLines')
// экземпляр Uni_ReportChannelExcel, созданный на клиенте и переданный отчету
Uni_ReportChannel repChannel;
// ...
{
Map mapReport;
real nLine; // номер строки данных отчета в Map - вдруг диапазона int не хватит...
void outputReportHeader()
{
UserInfo userInfo;
;
repChannel.initReportChannel(#ReportTemplatePath_RU + #ReportTemplateName);
select firstonly name from userInfo where userInfo.id == curuserid();
repChannel.insertReportValue(#fldHdrLine1, this.reportTitle());
repChannel.insertReportValue(#fldHdrLine2, strfmt("@DIS10758", currencyCode));
repChannel.insertReportValue(#fldHdrLine3, strfmt("Отчет сформирован: %1 %2, пользователь: %3",
today(), time2str(timenow(),0,0), userInfo.name));
repChannel.insertReportValue(#fldAccountNum,"@DIS8614");
// и т.д. - вставка полей шапки отчета
}
void outputReportBody()
{;
repChannel.outputReportBody(mapReport.pack(), #fldReportLines);
}
void outputReportFooter()
{;
// вставка итоговых полей отчета
// освобождение используемых COM-объектов
repChannel.finalize();
}
void dumpReportStr(str _p1, TransDate _p2, str _p3, Amount _p4)
{;
mapReport.insert(nLine,[_p1, // #fldAccountNum
_p2, // #fldTransDate
_p3, // #fldDocumentDesc
_p4]); // #fldAmount
nLine++;
}
void initReportStruct()
{
#CCADO
Array arrFields = new Array(Types::Container);
int i = 1;
;
arrFields.value(i, [#fldAccountNum, #adBSTR] ); i++;
arrFields.value(i, [#fldTransDate, #adDBDate]); i++;
arrFields.value(i, [#fldDocumentDesc, #adBSTR] ); i++;
arrFields.value(i, [#fldAmount, #adDouble]);
repChannel.initReportBuffer(arrFields.pack());
}
;
// поехали...
initReportStruct();
mapReport = new Map(Types::Real, Types::Container);
nLine = 1.0;
while select * from tmpTbl
order by TransDate
{
// подготовка данных к выводу и...
dumpReportStr(tmpTbl.AccountNum, tmpTbl.TransDate, tmpTbl.DocDesc, tmpTable.Amount);
}
// вывод в Excel
outputReportHeader();
outputReportBody();
outputReportFooter();
}
|