Показать сообщение отдельно
Старый 25.09.2006, 13:59   #3  
gl00mie is offline
gl00mie
Участник
MCBMSS
Most Valuable Professional
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
3,684 / 5788 (200) ++++++++++
Регистрация: 28.11.2005
Адрес: Москва
Записей в блоге: 3
Цитата:
Сообщение от Gustav Посмотреть сообщение
По классу - пара пожеланий. Первое. Я бы объединил методы getFieldValue и getNamedFieldValue в один универсальный getFieldValue. И плюс к этому нумерацию полей начал бы с единицы, невзирая на то, что в самом ADO первое поле - 0. Понимаю, что вопрос концептуально-идеологический. Я сам метался между 0 и 1, но в конце концов остановился на 1. Ну и что, что лишняя операция вычитания, зато получается нормальный наглядный натуральный ряд (блин, ненавижу циклы от 0 до Count-1).
Fixed Я тоже сначала думал, как делать индексацию полей и по номерам, и по названиям колонок, но чего-то совсем забыл про anytype Кроме того, нумерация начиная с 1 применительно к Excel, конечно, куда удобнее - в нем ведь тоже можно включить нумерацию колонок ("стиль ссылок R1C1"), а там она начинается как раз с 1.
Цитата:
У меня в "инструментальном ящичке" в некотором классе есть противоположный метод - setFieldValue, привожу его в качестве подспорья-иллюстрации. Воспользуйтесь при желании.
PHP код:
void setFieldValue(anytype _fldNameanytype _fldValueint _ordNum 0)
{
    
// _fldName - можно текстовое имя, а можно числовое, начиная с 1 (!), а не 0 как в самом ADO
    // _ordNum - дополнительный способ нумерации, если используются текстовые названия полей (чисто для наглядности самого кода)
 
    
anytype fldName;
 
    if (
typeof(_fldName) == Types::Integer)
        
fldName _fldName 1;
    else
        
fldName _fldName// текстовое представление поля
    
fld flds.Item(fldName);
    
fld.Value(_fldValue);

Честно говоря, не понял две вещи: зачем нужен параметр _ordNum, если он не используется, и зачем идет дополнительное присваивание fldName = _fldName. У меня работает просто такой код:
PHP код:
if(typeof(_fldId) == Types::Integer)
    
_fldId--;                           // ADO uses indexes starting 0, not 1
fld flds.Item(_fldId); 
А так, иллюстрацией я уже воспользовался
Цитата:
Второе пожелание. В методе getRecordCount я бы не торопился возвращать -1 в случае невозможности определения кол-ва записей через ADO. Всё же класс посвящен Excel'ю, а он нам не чужой. Можно, например, воспользоваться в Excel методом Range.CurrentRegion и далее Rows.Count минус первая заголовочная строка (если она есть). Ну, как-то так...
Меня, по правде сказать, вопрос использования Excel'евских COM-интерфейсов несколько смущает... Все же упор сделан на ADO, и экселевской специфики в классе - только определение названия активного листа, которое используется как название таблицы в выборке, да еще формат строки соединения... Во-первых, меня смущают такие вещи, как производительность: надо, конечно, тесты провести, но, сдается мне, если грузить Excel для того, чтобы посчитать количество строк в диапазоне, то это вызовет заметную задержку при открытии файла. Во-вторых, количество строк в диапазоне (range) и количество строк в выборке совпадут лишь в том случае, если использовать для получения Recordset обычный select * from. Но если развивать идею дальше, то select может оказаться с where, да еще и по нескольким листам книги Excel, и тогда в Recordset.RecordCount будет вовсе не равно Range.CurrenRegion.Rows.Count-1. В-третьих, в ADO и так есть возможность получить число строк в выборке, например, использовать статический курсор, а не forward-only, который используется в классе по умолчанию. Достаточно при создании экземпляра класса написать
PHP код:
#CCADO
// ...
excelImp = new Uni_ExcelImportADO(strFileName,  #adOpenStatic); 
Правда, опять-таки, это приводит к задержкам при открытии файла, потому что приходится для подсчета считывать все данные в буфер перед тем, как начать выдавать их. Впрочем, я сейчас провел небольшой тест, и выяснилось, что в простейших случаях это не столь критично. Для файла из 4-х полей (цифровой код, текстовое описание от 30 до 120 символов, еще два цифровых поля) и 8000 записей при 5 последовательных тестах на каждый этап среднее время у меня составило:
  • открытие 456 мс, считывание данных 8093 мс, курсор forward-only, имя листа определяется классом;
  • открытие 456 мс, считывание данных 8172 мс, курсор статический, имя листа определяется классом;
  • открытие 22 мс, считывание данных 7960 мс, курсор forward-only, имя листа указано в параметре;
  • открытие 22 мс, считывание данных 8067 мс, курсор статический, имя листа указано в параметре.
Измерения велись с помощью GetTickCount(), открытие - это создание экземпляра класса + вызов openFile(), считывание данных - это цикл выборки трех полей из каждой записи.
В общем, мне кажется, идеологически правильнее использовать для определения количества записей средства ADO, а не обходные маневры с использованием COM-интерфейсов Excel.
Во вложении - тестовый job, использованный для измерения скорости. Обновленный класс можно найти в первом сообщении темы.
Вложения
Тип файла: xpo jobTestImportFromExcelADO.xpo (3.7 Кб, 752 просмотров)

Последний раз редактировалось gl00mie; 08.01.2007 в 23:45.
За это сообщение автора поблагодарили: blokva (2), Hans (1), konopello (1), demon46 (1).