При интеграции 1С 7.7 со сторонними системами часто возникает необходимость читать или обновлять данные в таблицах формата DBF. Однако при попытке выполнения команд UPDATE или проходе по выборке SELECT с помощью провайдеров Microsoft JET OLEDB или VFPOLEDB разработчики столкнутся с критическими ошибками:
MoveNext() или при выполнении UPDATE с условием WHERE.Рассмотрим подробнее причины возникновения этих ошибок и проанализируем проверенные способы их решения.
Разберем механику работы провайдеров OLE DB. В заголовке каждого DBF-файла по смещению 28 (0x1C) содержится однобайтовый флаг, отвечающий за наличие структурного индекса .CDX. Если этот байт равен 0x01, OLE DB провайдер (как Microsoft JET, так и VFPOLEDB) автоматически пытается найти и подключить одноименный индексный файл.
Если таблицы создавались во внешних DOS-приложениях (например, на Clipper или FoxPro), индексные выражения часто включают функции пользователя или глобальные переменные приложения (например, CFG_SBFIO). Провайдер OLE DB в среде Windows не знает о существовании этих переменных и при попытке вычислить выражение индекса выдает ошибку о ненайденной переменной или сбивается с позиционирования по записям при перемещении курсора.
Стандартный код подключения через ADO выглядит следующим образом:
DBConn = CreateObject("ADODB.Connection");
DBConn.Open("Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data Source=" + СокрЛП(КаталогБазы) + ";" +
"Extended Properties=""DBASE IV;"";");
DBConn.Execute("UPDATE [tabl#DBF] SET FIO='Петров Василий Пупкин' WHERE KOD=131559");
Если поле KOD или любое другое поле таблицы участвует в вычисляемом индексе .CDX, стандартный вызов ADO завершается аварийно.
Наиболее надежный способ работы со сторонними DBF-файлами в разделенном режиме — использование внешней компоненты 1SQLite. Она позволяет монтировать произвольные DBF-файлы в качестве виртуальных таблиц в RAM-базу данных SQLite.
При таком подходе 1SQLite считывает DBF-файл на физическом уровне как набор байтовых записей, полностью игнорируя связанные файлы .CDX и вычисляемые индексные выражения Clipper/FoxPro.
Разберем пример кода выполнения запроса через 1SQLite:
Если ЗагрузитьВнешнююКомпоненту("1sqlite.dll") = 0 Тогда
Предупреждение("Не удалось загрузить 1sqlite.dll");
Возврат;
КонецЕсли;
БазаДанных = СоздатьОбъект("SQLiteBase");
БазаДанных.Открыть(":memory:"); // Открываем временную базу в памяти
Запрос = БазаДанных.СоздатьЗапрос();
// Монтируем внешний DBF-файл как виртуальную таблицу
СтрокаПодключения = "CREATE VIRTUAL TABLE ТаблКлиентов USING dbf('" + СокрЛП(ПутьКФайлу) + "', 'CP866');";
Запрос.ВыполнитьЗапрос(СтрокаПодключения);
// Выполняем обновление данных без использования OLE DB и без учета CDX-индексов
ТекстUPDATE = "UPDATE ТаблКлиентов SET FIO='Петров Василий Пупкин' WHERE KOD=131559;";
Запрос.ВыполнитьЗапрос(ТекстUPDATE);
Преимущества метода:
.CDX файлов.Если необходимо использовать именно ADO или штатный объект 1С XBase, можно временно программно отключить флаг структурного индекса в заголовке таблицы. Этот метод применяется только для редактирования полей, которые не входят в состав индексного выражения.
Проанализируем алгоритм выполнения:
ADODB.Stream).0x1C).0x01, меняем его на 0x00 и сохраняем файл.UPDATE или SELECT через ADO. Провайдер воспринимает файл как обычный DBF без индекса и успешно обрабатывает данные.0x01).Пример реализации сброса флага через ADODB.Stream:
Поток = СоздатьОбъект("ADODB.Stream");
Поток.Type = 1; // Binary
Поток.Open();
Поток.LoadFromFile(ПутьКФайлуDBF);
// Переходим к байту 28
Поток.Position = 28;
// Чтение и сброс флага CDX (0x00 - нет индекса, 0x01 - есть индекс)
// После изменения байта выполняется сохранение файла:
// Поток.SaveToFile(ПутьКФайлуDBF, 2);
После снятия флага структурного индекса (способ 2) для модификации данных можно использовать штатный объект 1С 7.7 XBase, который при отсутствии флага 0x01 не станет искать .CDX файл:
ДБФ = СоздатьОбъект("XBase");
ДБФ.ОткрытьФайл(ПутьКФайлуDBF); // Индексный файл не передаем!
Если ДБФ.Открыта() = 1 Тогда
ДБФ.КлючевоеПоле("KOD");
Если ДБФ.Найти(131559) = 1 Тогда
ДБФ.FIO = "Петров Василий Пупкин";
ДБФ.Записать();
КонецЕсли;
ДБФ.ЗакрытьФайл();
КонецЕсли;
При организации записи в сторонние DBF-файлы из 1С 7.7 важно учитывать специфику блокировок. Старые программы на DOS/Clipper и современные провайдеры Windows (OLE DB) используют разную логику блокировки файлов:
LockFileEx.По этой причине OLE DB провайдер может не увидеть блокировки строки, установленной DOS-программой. Для исключения повреждения данных запись рекомендуется выполнять точечно с минимальной задержкой удерживания открытого файла или через транзакции компоненты 1SQLite.