Примечание - большая часть написанного здесь текста
с примерами взята по памяти (пару лет назад изучал достаточно подробно,
поэтому может что-то в алгоритмах не работать - я ведь их не копировал
откуда-то, а прямо тут же и писал, так что за синтаксические ошибки
не пинайте) - на данный момент я активно OLE не пользуюсь (не из-за
каких-то проблем с самим OLE, а из-за отсутствия надобности в его использовании
в текущий момент).
Основные преимущества,
благодаря которым OLE активно используется:
- Для вызывающей
базы "по барабану" - какой тип вызываемой базы (DBF или SQL)
- Объектами вызываемой
базы можно управлять всеми известными методами работы с объектами
в 1С (т.е. со справочниками работают методы ВыбратьЭлементы(), ИспользоватьДату()
и т.п., с документами - ВыбратьДокументы() и т.п.), соответственно,
можно напрямую решить - стоит отрабатывать конкретные объекты базы
OLE или пропустить их.
Пример
1. Присоединение к базе 1С через OLE.
БазаОле=СоздатьОбъект("V77.Application"); // Получаем доступ к OLE объекту 1С
|
Локальная версия
(на одного пользователя): |
V77L.Application |
Сетевая версия: |
V77.Application |
Версия SQL: |
V77S.Application |
Далее вместо термина
"вызываемая база" будет написано просто "база OLE", а
вместо термина "вызывающая база" - "местная база"
Теперь, мы должны
знать несколько параметров для запуска базы OLE: Каталог базы, имя пользователя
и пароль. Ну, наверное, еще и желание запустить 1С в монопольном режиме
:)
КаталогБазыОЛе = "C:\program files\1cv77\МояБаза\";
ПользовательОле = "Администратор";
ПарольОле = "qwerty";
МонопольныйРежимOLE = " /m"; // для немонопольного запуска указать пустую строку!
ЗапускБезЗаставки = 1; // для появления заставки (например, чтобы наблюдать
// процесс запуска базы OLE визуально) поставьте здесь "0"
РезультатПодключения = БазаОле.Initialize ( БазаОле.RMTrade , "/d" +
СокрЛП(КаталогБазыОле) + " /n" + СокрЛП(ПользовательОле)+
" /p" + СокрЛП(ПарольОле) + МонопольныйРежимOLE,
?(ЗапускБезЗаставки = 1,"NO_SPLASH_SHOW",""));
Если РезультатПодключения = 0 Тогда
Предупреждение("Не удалось подключится к указанной базе - проверьте вводные!");
КонецЕсли;
|
Комментарий: функции СокрЛП() стоят в примере на случай,
если пользователь захочет указанные выше переменные сделать в форме
диалога, а проблема при этом состоит в том, что в алгоритм программа
передаст полное значение реквизита (т.е. допишет в конце значения то
количество пробелов, которое необходимо для получения полной длины строки
(указана в свойствах реквизита диалога)).
Пример 2. Доступ
к объектам базы OLE.
Запомните на будущее
как непреложный факт:
- Из местной базы
в базу OLE (и, соответственно, наоборот) напрямую методом присвоения
можно перенести только числовые значения, даты и строки ограниченной
длины!!! Т.е. местная база поймет прекрасно без дополнительных алгоритмов
преобразования полученного значения только указанные типы значений.
Кроме того, под ограничением строк подразумевается проблемы с пониманием
в местной базе реквизитов объектов базы OLE типа "Строка неограниченной
длины". К этому же еще надо добавить и периодические реквизиты. Естественно,
под методом присвоения подразумеваются и попытки сравнить объекты
разных баз в одном условии (например, в алгоритмах "Если" или "Пока"
и т.п.).
- Есть проблемы при
попытке перенести "пустую" дату - OLE может ее конвертировать, например,
в 31.12.1899 года и т.п. Поэтому вам лучше заранее выяснить те значения,
которые могут появится в местной базе при переносе "пустых" дат, чтобы
предусмотреть условия преобразования их в местной базе.
A) Доступ к константам базы OLE:
ЗначениеКонстантыOLE = БазаОле.Константа.ДатаЗапретаРедактирования; |
Б) Доступ к справочникам и документам базы OLE
(через функцию "CreateObject"):
СпрOLE = БазаОле.CreateObject("Справочник.Фирмы"); // "СоздатьОбъект" в OLE не работает!
ДокOLE = БазаОле.CreateObject("Документ.РасходнаяНакладная"); |
После создания объекта
справочника или документа к ним применимы все методы, касающиеся таких
объектов в 1С:
СпрОле.ВыбратьЭлементы();
Пока СпрОле.ПолучитьЭлемент()=1 Цикл
Сообщить(Спр.Наименование);
КонецЦикла; |
Заметьте, что если
вместо "Сообщить(Спр.Наименование)" вы укажете "Сообщить(Спр.ТекущийЭлемент())",
то вместо строкового/числового представления этого элемента программа
выдаст вам в окошке сообщение "OLE". Именно это я и имел в виду, когда
говорил, что напрямую мало что можно перенести. Т.е. не будут работать
следующие методы (ошибки 1С не будет, но и результат работы будет нулевой).
Рассмотрим следующий пример:
СпрOLE = БазаОле.CreateObject("Справочник.Фирмы"); // это справочник в базе OLE
Док = СоздатьОбъект("Документ.РасходнаяНакладная"); // а это документ в местной базе
Док.Новый(); // создаем новый документ в местной базе
СпрOLE.НайтиПоКоду(1,0); // спозиционируем в базе OLE
// на фирме с кодом "1".
Док.Фирма = СпрOLE.ТекущийЭлемент(); // такой метод не сработает, т.к. справа от "=" стоит
// объект не местной базы, и местная база 1С его не понимает!
|
Однако, сработает следующий метод:
Спр = СоздатьОбъект("Справочник.Фирмы"); // создаем объект справочника местной базы
Спр.НайтиПоНаименованию(СпрОле.Наименование,0,0); // Или Спр.найтиПоКоду(СпрОле.Код,0);
// т.е. СпрОле.Код и Спр.наименование
// являются обычными числовыми/строковыми
// значениями, которые понимает местная база!
Док.Фирма = Спр.ТекущийЭлемент(); // Вот теперь все в порядке, т.к. с обоих сторон метода
// стоят объекты только местной базы!
|
Отсюда вывод: возможность
доступа к объектам базы 1С через OLE требуется, в основном, только для
определенной задачи - получить доступ к реквизитам определенного элемента
справочника или документа. Однако, не забываем, что объекты базы OLE
поддерживают все методы работы с ними, в т.ч. и "Новый()", т.е. приведем
пример противоположный предыдущему:
ДокОле = CreateObject("Документ.РасходнаяНакладная"); // Создаем документ в базе OLE
ДокОле.Новый();
Спр = СоздатьОбъект("Справочник.Фирмы"); // В местной базе получаем доступ к справочнику
Спр.НайтиПоКоду(1,0); // Находим в местной базе фирму с кодом 1 (если есть)
ДокОле.Фирма = Спр.ТекущийЭлемент(); // такой метод не сработает
|
Однако, сработает следующий метод:
СпрОле = БазаОле.CreateObject("Справочник.Фирмы"); // создаем объект справочника базы OLE
СпрОле.НайтиПоНаименованию(Спр.Наименование,0,0); // Или СпрОле.найтиПоКоду(Спр.Код,0);
// т.е. Спр.Код и Спр.Наименование являются обычными числовыми/строковыми значениями,
// которые понимает база OLE!
ДокОле.Фирма = СпрОле.ТекущийЭлемент(); // Вот теперь все в порядке, т.к. с обоих сторон
// метода стоят объекты базы OLE!
ДокОле.Записать(); // запишем документ в базе OLE
Если ДокОле.Провести()=0 тогда
Сообщить("Не смогли провести документ!");
КонецЕсли; |
В) Доступ к регистрам базы OLE (Не сложнее справочников
и документов):
РегОле=БазаOLE.CreateObject("Регистр.ОстаткиТоваров");
РегОле.ВыбратьИтоги();
Пока РегОле.ПолучитьИтог()=1 Цикл // Не забываем, что надо указывать наименование!
Сообщить("Остаток для " + РегОле.Товар.Наименование+ " на складе " +
РегОле.Склад.Наименование + " равен " + РегОле.ОстатокТовара);
КонецЦикла; |
Г) Доступ к перечислениям базы OLE (аналогичен
константе):
ЗначениеПеречисленияOLE = БазаОле.Перечисление.Булево.НеЗнаю; // :)
|
Заметьте, что пользы
для местной базы от переменной "ЗначениеПеречисленияOLE" особо-то и
нет, ведь подобно справочнику и документу перечисление также напрямую
недоступно для местной базы. Пожалуй, пример работы с ними может быть
следующим (в качестве параметра условия):
СмотретьТолькоВозвратыПоставщикам = 1; // предположим, что это - флажок в форме диалога,
// который мы либо устанавливаем, либо снимаем
ДокОле = БазаОле.CreateObject("Документ.РасходнаяНакладная");
ДокОле.ВыбратьДокументы(НачДата,КонДата); // НачДата и КонДата - также реквизиты формы
// диалога, но база OLE прекрасно их понимает -
// ведь это же даты!
Пока ДокОле.ПолучитьДокумент()=1 Цикл
Если СмотретьТолькоВозвратыПоставщикам = 1 Тогда
Если ДокОле.ПризнакНакладной <> БазаОле.Перечисление.ПризнРасхНакл.ВозвратПоставщику Тогда
Продолжить;
КонецЕсли;
Иначе
Если ДокОле.ПризнакНакладной = БазаОле.Перечисление.ПризнРасхНакл.ВозвратПоставщику Тогда
Продолжить;
КонецЕсли;
КонецЕсли;
Сообщить(ДокОле.Вид() + " № "+ДокОле.НомерДок + " от " + ДокОле.датаДок);
КонецЦикла; |
Д) Доступ к счетам базы OLE:
СчтОле=БазаОле.CreateObject("Счет");
СчтОле.НайтиПоКоду("10.5"); // нашли в базе OLE счет 10.5
|
Е) Доступ к ВидамСубконто базы OLE (аналогичен
перечислению):
ВидСубконтоКонтрагентыОле = БазаОле.ВидыСубконто.Контрагенты; |
По аналогии со справочниками
и документами работает объект "Периодический", план счетов работает
по аналогии с ВидомСубконто, ну и далее в том же духе… Отдельную главу
посвятим запросу, а сейчас… стоп. Еще пункт забыл!
Ж) Доступ к функциям и процедурам глобального
модуля базы OLE!
Как же я про это забыл-то,
а? Поскольку при запуске базы автоматически компилируется глобальный
модуль, то нам становятся доступны функции и процедуры глобального модуля
(поправлюсь - только те, у которых стоит признак "Экспорт"). Плюс к
ним еще и различные системные функции 1С. А доступны они нам через функцию
1С OLE - EvalExpr(). Приведем примеры работы с базой OLE:
ДатаАктуальностиОле = БазаОле.EvalExpr("ПолучитьДатуТА()");
// Возвращает дату актуальности
ИмяПользователяОле = БазаОле.EvalExpr("ИмяПользователя()");
// возвращает строку
//
// попробуем теперь получить числовое значение НДС у элемента номенклатуры
// через функцию глобального модуля ПроцентНДС(СтавкаНДС) Экспорт!
ТовОле = БазаОле.CreateObject("Справочник.Номенклатура");
ТовОле.ВыбратьЭлементы();
// Найдем элемент справочника (не группа!)
Пока ТовОле.ПолучитьЭлемент()=1 Цикл
Если ТовОле.ЭтоГруппа()=0 Тогда
Прервать;
КонецЕсли;
КонецЦикла;
ЧисловоеЗначениеПроцентаНДСТовараОле = БазаОле.EvalExpr("ПроцентНДС(Перечисление.ЗначенияНДС." +
ТовОле.СтавкаНДС.Идентификатор()+")"); |
На самом деле, в последней
строке примера я исхитрился и забежал немного вперед. Дело в том, что
как и запрос (см. отдельную главу), так и EvalExpr() выполняются
внутри базы OLE, причем команды передавается им обычной строкой, и поэтому
надо долго думать, как передать необходимые ссылки на объекты базы OLE
в строке текста местной базы. Так что, всегда есть возможность поломать
голову над этим…
Алгоритмы
преобразования объектов в "удобоваримый вид" между базами.
Ясно, что алгоритмы
преобразования нужны не только для переноса объектов между и базами,
но и для такой простой задачи, как попытки сравнить их между собой.
И еще раз обращу внимание:
ОБЪЕКТЫ ОДНОЙ БАЗЫ ПРЕКРАСНО ПОНИМАЮТ ДРУГ ДРУГА, ПРОБЛЕМЫ ВОЗНИКАЮТ
ТОЛЬКО ТОГДА, КОГДА ВЫ НАЧИНАЕТЕ СВЯЗЫВАТЬ МЕЖДУ СОБОЙ ОБЪЕКТЫ РАЗНЫХ
БАЗ, т.е. команда
ДокОле.Фирма=СпрОле.ТекущийЭлемент();
// где ДокОле - документ базы OLE, а СпрОле - справочник "Фирмы" базы OLE
будет прекрасно работать
без ошибок. Не забывайте это, чтобы не перемудрить с алгоритмами!
Итак, повторяюсь,
что напрямую перенести, да и просто сравнить можно только даты (причем
не "пустые"), числа и строки ограниченной длины. Итак, как же нам сравнить
объекты разных баз (не числа, не даты, не строки), т.е. как их преобразовать
в эту самую строку/число/дату.