Показать сообщение отдельно
Старый 24.04.2006, 20:54   #6  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
ADODB.Recordset в оперативной памяти без связи с БД
Цитата:
Сообщение от macklakov
Лучше в аксовскую базу со стороны не лезть. Получишь блокировки, в самый напряженный момент.
Однако, нашёлся «рояль в кустах». Теперь лезем не стороны, а изнутри!
На мой взгляд – просто чума…

Recordset в оперативной памяти (как массив)! Без объекта Connection! Сам по себе, без привязки к источнику данных. При этом обладает свойствами обычного Recordset-а (работают всякие MoveLast, MoveFirst и т.п. – конечно, надо потестировать, но MoveFirst работает точно – см. джоб ниже). Можно добавлять записи, редактировать их. Состав полей тоже определяем сами.

В качестве примера – джоб ниже, опять-таки выводящий в Excel список сотрудников. Ничего предварительно настраивать не надо, просто запускайте.
X++:
static void Job_TestADO_2(Args _args)
{
// ----------------------------------------------------------------------------
// ADODB.Recordset в оперативной памяти без привязки к источнику данных
// ----------------------------------------------------------------------------
    EmplTable emplTable;
    COM rstAxa;    // ADO: Recordset
    COM flds, fld; // ADO: Fields, Field
    COM xlApp;            // Excel.Application
    COM wbks, wbk;        // Workbooks, Workbook
    COM wkss, wks;        // Worksheets, Worksheet
    COM rng, cell, rngCR; // все Range
    COM font;             // Range.Font
    COM entCol;           // Range.EntireColumn
    COM actWin;           // Excel.Application.ActiveWindow
    int i, iMax;
// ============================================================================
    // СНАЧАЛА ВЛОЖЕННАЯ ФУНКЦИЯ
// ----------------------------------------------------------------------------
    // функция для задания типа поля нашего Recordset-а в оперативной памяти
    // в данном демо-джобе используется для наглядности
    // для простоты используем всего 3 типа данных: число, строка и дата
    int adoTypeToExcel(str _type)
    {
        switch (_type)
        {
        // используются значения констант перечисления DateTypeEnum из топика TypeProperty (ADO)
        // (см. справку по ADO в файле ADO210.CHM - можно поискать на своем компе)
            case 'num' : return   5; // adDouble
            case 'str' : return   8; // adBSTR
            case 'date': return 133; // adDBDate
        }
        return 8;
    }
// ============================================================================
    // ТЕПЕРЬ ОСНОВНОЙ ПРОЦЕСС
    // Recordset создается в оперативной памяти - без Connection!
    rstAxa = new COM('ADODB.Recordset');
    // формируем структуру нашего Recordset-а в "мозгах"
    flds = rstAxa.Fields();
    flds.Append('Name'         , adoTypeToExcel('str' ));
    flds.Append('PhoneLocal'   , adoTypeToExcel('str' ));
    flds.Append('EmplId'       , adoTypeToExcel('str' ));
    flds.Append('CellularPhone', adoTypeToExcel('str' ));
    flds.Append('UserId'       , adoTypeToExcel('str' ));
    flds.Append('BirthDate'    , adoTypeToExcel('date'));
    flds.Append('RecId'        , adoTypeToExcel('num' ));
    // и наконец открываем его
    rstAxa.Open();
// ----------------------------------------------------------------------------
    while select emplTable order by Name
    {
    // бежим по таблице "Список сотрудников" Axapta
    // и добавляем записи (выбранные поля) в Recordset в оперативной памяти
        rstAxa.AddNew();
            fld = flds.Item('Name'         ); fld.Value(emplTable.Name         );
            fld = flds.Item('PhoneLocal'   ); fld.Value(emplTable.PhoneLocal   );
            fld = flds.Item('EmplId'       ); fld.Value(emplTable.EmplId       );
            fld = flds.Item('CellularPhone'); fld.Value(emplTable.CellularPhone);
            fld = flds.Item('UserId'       ); fld.Value(emplTable.UserId       );
            fld = flds.Item('BirthDate'    ); fld.Value(emplTable.BirthDate    );
            fld = flds.Item('RecId'        ); fld.Value(emplTable.RecId        );
        rstAxa.Update();
    }
    // к этому моменту в оперативной памяти сформирована НАША таблица "Список сотрудников"
// ----------------------------------------------------------------------------
    // перед выгрузкой в Excel встанем на первую запись НАШЕЙ ТАБЛИЦЫ В ПАМЯТИ
    // и изменим имя сотрудника, дату его рождения и ID
    // НЕ БОЙТЕСЬ!!! Аксаптовская таблица EmplTable при этом НЕ ЗАТРАГИВАЕТСЯ!!! :)))
    rstAxa.MoveFirst();
    fld = flds.Item('Name'     ); fld.Value('Самый молодой cотрудник с очень длинным именем');
    fld = flds.Item('BirthDate'); fld.Value(1\3\2006); // 1-е марта 2006 года
    fld = flds.Item('EmplId'   ); fld.Value('000333'); 
    // потом обратите внимание, что в Excel ведущие нули у 000333 сохранятся!
    rstAxa.Update();
// ----------------------------------------------------------------------------
    // готовим новую рабочую книгу Excel для приема данных из Axapta:
    xlApp = new COM('Excel.Application');
    xlApp.Visible(true);
    wbks = xlApp.Workbooks();
    wbk  = wbks.Add();
    wkss = wbk.Worksheets();
    wks  = wkss.Item(1);
    wks.Name('AdoTestSheet');
    rng  = wks.Range('A1');
// ----------------------------------------------------------------------------
    // выводим строку имен полей (1-я строка листа Excel)
    flds = rstAxa.Fields();
    iMax = flds.Count() - 1;
    for (i = 0; i <= iMax; i += 1)
    {
        fld = flds.Item(i);
        cell = rng.Offset(0, i);
        cell.Value2(fld.Name());
    }
    rngCR = rng.CurrentRegion();
    font = rngCR.Font();
    font.Bold(true); // делаем выведенные заголовки жирным шрифтом
// ----------------------------------------------------------------------------
    // выводим данные, начиная со 2-й строки листа Excel
    cell = rng.Offset(1, 0);
    cell.CopyFromRecordset(rstAxa);
// ----------------------------------------------------------------------------
    // подгоняем ширину столбцов Excel
    rngCR = rng.CurrentRegion();
    entCol = rngCR.EntireColumn();
    entCol.AutoFit();
    // замораживаем строку заголовков Excel
    cell.Select();
    actWin = xlApp.ActiveWindow();
    actWin.FreezePanes(true);
// ----------------------------------------------------------------------------
    rstAxa.Close();
}
За это сообщение автора поблагодарили: slava (1), CDR (2), new-comer (1), kvg6 (1), konopello (2), wojzeh (1), raniel (1), Antoncheg (1), Kabardian (3), Roman N. Krivov (1), kpoxa (1), SuperStar88 (1).