Рассмотрим достаточно распространенную архитектурную задачу: имеется сторонняя база данных, которая формирует файл в формате DBF. Этот файл физически располагается на локальных компьютерах пользователей, при этом структура файла у всех одинаковая, а наполнение — разное. Наша цель — прочитать эти данные и использовать их для построения отчета с помощью Системы Компоновки Данных (СКД) на 64-битном сервере приложения 1С. Проанализируем ситуацию и разберем по шагам все возможные способы решения этой проблемы.
Первое препятствие, с которым мы сталкиваемся — это разрядность сервера. Многие разработчики по привычке пытаются настроить внешние источники данных и ищут системные ODBC или OLE DB драйверы. На 64-битном сервере 32-битные драйверы работать не будут. Если вам принципиально нужны драйверы, придется устанавливать 64-битный пакет Microsoft Access Database Engine.
Однако мы поступим проще и надежнее. Платформа 1С:Предприятие имеет встроенный объект XBase, который нативно читает и записывает DBF-файлы. Он отлично работает как в 32-битной, так и в 64-битной среде без установки дополнительных компонентов системы.
Рассмотрим, как прочитать данные и поместить их в Таблицу Значений:
Функция ПрочитатьDBFВТаблицу(ПутьКФайлу)
ТаблицаДанных = Новый ТаблицаЗначений;
ФайлDBF = Новый XBase;
ФайлDBF.Кодировка = КодировкаXBase.OEM; // или ANSI, в зависимости от файла
ФайлDBF.ОткрытьФайл(ПутьКФайлу);
Если Не ФайлDBF.Открыта() Тогда
Сообщить("Не удалось открыть файл DBF!");
Возврат ТаблицаДанных;
КонецЕсли;
// Создаем колонки в ТЗ по структуре DBF
Для Каждого Поле Из ФайлDBF.Поля Цикл
ТаблицаДанных.Колонки.Добавить(Поле.Имя);
КонецЦикла;
// Читаем данные
ФайлDBF.Первая();
Пока Не ФайлDBF.ВКонце() Цикл
НоваяСтрока = ТаблицаДанных.Добавить();
Для Каждого Поле Из ФайлDBF.Поля Цикл
НоваяСтрока[Поле.Имя] = ФайлDBF[Поле.Имя];
КонецЦикла;
ФайлDBF.Следующая();
КонецЦикла;
ФайлDBF.ЗакрытьФайл();
Возврат ТаблицаДанных;
КонецФункции
Если данные из файла нужны только для формирования отчета и их не нужно хранить в базе 1С, оптимальным решением будет использование Таблицы Значений. Выясним, как передать ее в СКД, если в отчете уже используется запрос к базе.
Имя объекта, содержащего данные укажем, например, ДанныеDBF. Добавим необходимые поля, совпадающие с колонками нашей Таблицы Значений.Теперь программно инициализируем отчет. Подготовим структуру ВнешниеНаборы и передадим ее в ПроцессорКомпоновкиДанных:
// Получаем ТЗ из файла
ТаблицаDBF = ПрочитатьDBFВТаблицу(ПутьКФайлуЛокально);
ВнешниеНаборыДанных = Новый Структура;
// Ключ структуры должен строго совпадать с именем объекта в СКД!
ВнешниеНаборыДанных.Вставить("ДанныеDBF", ТаблицаDBF);
СхемаКомпоновки = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Настройки = СхемаКомпоновки.НастройкиПоУмолчанию;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновки, Настройки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
// Передаем внешние наборы
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
Связь наборов данных на уровне СКД иногда работает не так гибко, как обычный SQL-запрос, особенно если требуется внутреннее или полное соединение. Посмотрим на альтернативный метод, который позволяет использовать переданную таблицу прямо в тексте запроса СКД.
Для этого в запросе СКД мы используем конструкцию ПОМЕСТИТЬ, принимая таблицу как параметр:
ВЫБРАТЬ
*
ПОМЕСТИТЬ ВТ_ДанныеИзФайла
ИЗ
&ТаблицаDBF КАК ВнешниеДанные
;
//////////////////////////////////////////////////
ВЫБРАТЬ
РегистрПродажи.Номенклатура,
Файл.Количество
ИЗ
ВТ_ДанныеИзФайла КАК Файл
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.Продажи.Обороты КАК РегистрПродажи
ПО Файл.Артикул = РегистрПродажи.Номенклатура.Артикул
При программном формировании отчета нам останется только установить значение параметра ТаблицаDBF, передав туда нашу сформированную Таблицу Значений.
Если логика работы требует не просто разового вывода отчета, а сохранения загруженных данных на какое-то время (например, для последующего анализа или распределенной обработки), нам потребуется создать объект метаданных. Разберем, что выбрать: Справочник или Регистр Сведений.
Регистр Сведений предпочтительнее. Справочник при записи создает уникальные ссылки (GUID), расходует больше ресурсов и оставляет «мусор», если ссылки где-то зависнут. Регистр сведений работает быстрее и не ссылочный.
Проанализируем возможную проблему: в DBF-файле могут оказаться дублирующиеся строки. Если просто попытаться записать их в независимый Регистр Сведений, платформа выдаст ошибку о неуникальности записи (конфликт ключевых полей).
Чтобы этого избежать, мы создадим Регистр Сведений со следующей структурой:
ИмяКомпьютера (строка) — для разделения данных разных пользователей.НомерСтрокиФайла (число) или Идентификатор (УникальныйИдентификатор) — это ключевое поле сделает каждую загружаемую строку абсолютно уникальной, независимо от того, дублируются ли сами бизнес-данные в DBF.Перед началом загрузки нового файла в регистр, мы программно очищаем записи по конкретному измерению ИмяКомпьютера. После этого СКД сможет брать данные напрямую из регистра обычным запросом.
Важное замечание про Журнал Регистрации: Отключить запись в журнал регистрации программно только на момент загрузки для одного регистра или пользователя невозможно. Настройки логирования задаются глобально в Конфигураторе для каждого объекта метаданных. Если вы не хотите, чтобы временные записи засоряли лог, вам нужно в свойствах самого Регистра Сведений в Конфигураторе установить свойство «История данных» и настройки журнала регистрации в положение «Не регистрировать».