Профессия — 1С

Рукопашный бой Карташ

Категории

Таблица значений. Основные приемы работы.

рубрики: Язык программирования 1С | Дата: 13 Июль, 2017
Скачать обработку с примерами из статьи: ValueTable.epf
Платформа: 8.3; Тип формы: управляемая.

В процессе разработки и отладки кода 1С очень часто используется такой объект как Таблица значений. Визуально его можно представить как обычную двумерную таблицу. Поэтому он очень легок для человеческого восприятия. А свойства и методы этого объекта позволяют работать как с его строками, так и с колонками. В этой статье рассмотрим как можно создавать таблицу значений средствами языка программирования 1С, а также наиболее часто встречающиеся приемы работы с ней.




В качестве примера давайте создадим простейшую таблицу значений в которой будет отображаться приход товара на склад.

Дата Наименование товара Количество
01.07.2017 Ручка 10
02.07.2017 Карандаш 7
03.07.2017 Карандаш 8
04.07.2017 Лампа 2

А потом рассмотрим различные приемы работы с ней.

Ограничение использования

Если открыть синтакс-помощник и посмотреть где доступна таблица значений, то мы увидим, что она недоступна на тонком клиенте. Соответственно при использовании управляемых форм мы сможем работать с ней только на сервере, т.е. в процедурах и функциях перед которыми установлена директива компиляции &НаСервере.




И конечно же мы не сможем вернуть таблицу значений из серверной функции в клиентскую.

Создание таблицы значений

Для программного создания таблицы значений нам необходимо с помощью конструктора создать сам объект, потом создать необходимые колонки, и наконец заполнить ее строками. Вот код функции которая создаст и вернет нам таблицу, которая приведена выше:




&НаСервере
Функция ЗаполнитьТаблицуЗначений()

	//Создаем таблицу
	ТаблицаТовары = Новый ТаблицаЗначений;

	//Добавляем колонки
	ТаблицаТовары.Колонки.Добавить("Дата", Новый ОписаниеТипов("Дата"));
	ТаблицаТовары.Колонки.Добавить("НаименованиеТовара", Новый ОписаниеТипов("Строка"));
	ТаблицаТовары.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));

	//Добавляем в таблицу строки
	НоваяСтрока = ТаблицаТовары.Добавить();
	НоваяСтрока.Дата = '20170701';
	НоваяСтрока.НаименованиеТовара = "Ручка";
	НоваяСтрока.Количество = 10;

	НоваяСтрока = ТаблицаТовары.Добавить();
	НоваяСтрока.Дата = '20170702';
	НоваяСтрока.НаименованиеТовара = "Карандаш";
	НоваяСтрока.Количество = 7;

	НоваяСтрока = ТаблицаТовары.Добавить();
	НоваяСтрока.Дата = '20170703';
	НоваяСтрока.НаименованиеТовара = "Карандаш";
	НоваяСтрока.Количество = 8;

	НоваяСтрока = ТаблицаТовары.Добавить();
	НоваяСтрока.Дата = '20170704';
	НоваяСтрока.НаименованиеТовара = "Лампа";
	НоваяСтрока.Количество = 2;

	Возврат ТаблицаТовары;

КонецФункции

Обход строк таблицы значений

Очень часто при работе с таблицами значений возникает задача обхода всех ее строк. Делается это с помощью циклов. Причем можно это делать как с использованием коллекции строк таблицы значений, когда мы последовательно получаем строки таблицы значений из коллекции строк, так и с использованием счетчика, когда мы получаем строку таблицы по ее индексу. Как правило используется первый способ — с обходом коллекции строк:




Для каждого СтрокаТаблицы Из ТаблицаТовары Цикл

	Сообщение = Новый СообщениеПользователю;
	Сообщение.Текст = Строка(СтрокаТаблицы.Дата) + "; " + СтрокаТаблицы.НаименованиеТовара + "; " + СтрокаТаблицы.Количество;
	Сообщение.Сообщить();

КонецЦикла;

Второй способ применяется гораздо реже, как правило когда первый не подходит по каким то причинам. Пример рассмотрим позднее, когда будем говорить про удаление строк из таблицы значений.

Поиск значения

Метод Найти(ИскомоеЗначение, [СписокКолонок]) возвращает строку таблицы в которой есть поле с нужным нам значением. Если значение не найдено, возвращается Неопределено. Список колонок в которых будет производиться поиск указывать необязательно, в этом случае поиск будет производиться во всех полях таблицы значений. Данный метод как правило используется для проверки наличия в таблице строки с искомым значением. Например, в момент обхода в цикле какой-то коллекции, мы формируем таблицу значений в которой значения некоторого поля не должны повторяться дважды. Тогда мы с помощью метода Найти() проверяем наличие строки с этим значением, и если получили Неопределено, тогда добавляем новую строку, в противном случае не делаем ничего. Применительно к нашему примеру давайте сделаем поиск строки со значением «Карандаш»:




СтрокаТаблицы = ТаблицаТовары.Найти("Карандаш");
Если СтрокаТаблицы = Неопределено Тогда

	Сообщение = Новый СообщениеПользователю;
	Сообщение.Текст = "Товар не найден";
	Сообщение.Сообщить();

Иначе

	НомерСтроки = ТаблицаТовары.Индекс(СтрокаТаблицы) + 1;

	Сообщение = Новый СообщениеПользователю;
	Сообщение.Текст = "Товар найден в строке №" + НомерСтроки;
	Сообщение.Сообщить();

КонецЕсли;

В исходной таблице у нас две строки с товаром «Карандаш», но найдена будет только первая из них. Поэтому данный метод не представляет особой ценности, если нам надо получить все строки с заданным значением. Следует понимать, что найденная строка — это по сути ссылка на строку таблицы значений, и если мы проделаем с ее полями какие-либо манипуляции, то это отразится на исходной таблице. Например если выполнить вот такой код:




СтрокаТаблицы = ТаблицаТовары.Найти("Карандаш");
СтрокаТаблицы.Количество = 100;

то мы обнаружим, что во второй строке нашей исходной таблицы соответствующим образом изменилось количество товара:

Дата Наименование товара Количество
01.07.2017 Ручка 10
02.07.2017 Карандаш 100
03.07.2017 Карандаш 8
04.07.2017 Лампа 2

Поиск нескольких строк по условию

В отличие от предыдущего метода, метод НайтиСтроки(СтруктураПоиска) возвращает не одну, а сразу все строки таблицы значений, которые удовлетворяют условию поиска. Точнее возвращается массив, каждый элемент которого представляет собой ссылку на строку таблицы значений. В качестве параметра метод использует структуру, где ключом является имя колонки, а значением — искомое значение. Удобно использовать, когда нам надо выбрать несколько строк по определенному условию, и проделать с ними какие-то действия. Допустим, нам надо в нашей таблице заменить наименование «Карандаш» на «Карандаш автоматический». В этом случае нам поможет следующий код:




СтруктураОтбора = Новый Структура;
СтруктураОтбора.Вставить("НаименованиеТовара", "Карандаш");

МассивСтрок = ТаблицаТовары.НайтиСтроки(СтруктураОтбора);

Для каждого СтрокаТаблицы Из МассивСтрок Цикл

	СтрокаТаблицы.НаименованиеТовара = "Карандаш автоматический";

КонецЦикла;

Структура для поиска может быть и более сложной. Например, мы можем добавить еще одно условие по колонке Дата:




СтруктураОтбора = Новый Структура;
СтруктураОтбора.Вставить("НаименованиеТовара", "Карандаш");
СтруктураОтбора.Вставить("Дата", '20170703');

Удаление строк из таблицы значений

Очевидно, что мы будем рассматривать удаление строк из таблицы значений по какому-то условию. В противном случае у нас произойдет просто очистка всей таблицы, что не имеет особого смысла. И на первый взгляд эта операция кажется достаточно простой. Первое, что приходит в голову — это перебор в цикле всех строк, проверка на выполнение условия, и если условие выполняется, то удаление текущей строки. Но на самом деле такой способ не всегда отрабатывает корректно. Давайте убедимся в этом на нашем примере. Удалим из таблицы все записи с наименованием «Карандаш»:




Для каждого СтрокаТаблицы Из ТаблицаТовары Цикл

	Если СтрокаТаблицы.НаименованиеТовара = "Карандаш" Тогда

		ТаблицаТовары.Удалить(СтрокаТаблицы);

	КонецЕсли;

КонецЦикла;

Но в итоге мы наблюдаем следующую картину

Дата Наименование товара Количество
01.07.2017 Ручка 10
03.07.2017 Карандаш 8
04.07.2017 Лампа 2

То есть у нас удалилась только одна строка вместо двух. Такое происходит когда строки, удовлетворяющие условию, следуют сразу же одна за другой. В этом случае при удалении первой строки, которая удовлетворяет условию, происходит сдвиг всех следующих за ней строк на одну вверх. Но курсор в выборке уже установлен на следующей строке, поэтому строка следующая за удаленной и занявшая ее место никак не обрабатывается. Что же делать в таком случае? Я обычно использую также обход строк в цикле, но не сверху вниз, а наоборот — снизу вверх. В этом случае сдвиг строк не страшен, т.к. нижние строки уже обработаны. При этом приходится вместо обхода коллекции строк использовать получение строки по индексу в цикле со счетчиком. Вот таким образом:




Индекс = ТаблицаТовары.Количество() - 1;
Пока Индекс >= 0 Цикл

	СтрокаТаблицы = ТаблицаТовары.Получить(Индекс);

	Если СтрокаТаблицы.НаименованиеТовара = "Карандаш" Тогда
		ТаблицаТовары.Удалить(СтрокаТаблицы);
	КонецЕсли;

	Индекс = Индекс - 1;

КонецЦикла;

И наконец попробуем с помощью метода НайтиСтроки() сразу получить все нужные строки, и удалить их поочередно:




СтруктураОтбора = Новый Структура;
СтруктураОтбора.Вставить("НаименованиеТовара", "Карандаш");

МассивСтрок = ТаблицаТовары.НайтиСтроки(СтруктураОтбора);

Для каждого СтрокаТаблицы Из МассивСтрок Цикл

	ТаблицаТовары.Удалить(СтрокаТаблицы);

КонецЦикла;

И в результате получаем:

Дата Наименование товара Количество
01.07.2017 Ручка 10
04.07.2017 Лампа 2

То есть такой метод тоже работает.

Группировка

Допустим, что нас больше не интересует дата, и мы хотим получить по каждому наименованию общее количество. То есть привести исходную таблицу вот к такому виду:

Наименование товара Количество
Ручка 10
Карандаш 15
Лампа 2

В этом случае нам надо сгруппировать строки таблицы. Напомню, что группировка в языке запросов также активно используется. А в таблице значений для этого используется метод Свернуть(КолонкиГруппировок, КолонкиСуммирования). В общем то, чтобы достигнуть результата нам потребуется всего одна строчка кода:




ТаблицаТовары.Свернуть("НаименованиеТовара", "Количество");

Сериализация таблиц значений

Таблица значений может сериализоваться с помощью объекта СериализаторXDTO. Проще говоря таблицу значений можно записать в формате XML или JSON, что открывает широкие возможности для передачи таблиц значений в качестве параметров при обмене данными. В том числе и через веб-сервисы.Рассмотрим использование обоих форматов.

Сериализация с использованием XML

В качестве примера выгрузим таблицу значений в строку XML, а потом создадим копию таблицы выполнив загрузку из строки XML:




ЗаписьХМЛ = Новый ЗаписьXML;
ЗаписьХМЛ.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьХМЛ, ТаблицаТовары);
СтрокаХМЛ = ЗаписьХМЛ.Закрыть();

ЧтениеХМЛ = Новый ЧтениеXML;
ЧтениеХМЛ.УстановитьСтроку(СтрокаХМЛ);
ТаблицаКопияХМЛ = СериализаторXDTO.ПрочитатьXML(ЧтениеХМЛ);
ЧтениеХМЛ.Закрыть();

Сериализация с использованием JSON

Начиная с версии платформы 8.3.7.1759 появилась возможность сериализации прикладных типов 1С:Предприятия в JSON. Принцип использования тот же, что и для XML:




ЗаписьJS = Новый ЗаписьJSON;
ЗаписьJS.УстановитьСтроку();
СериализаторXDTO.ЗаписатьJSON(ЗаписьJS, ТаблицаТовары, НазначениеТипаXML.Явное);
СтрокаJS = ЗаписьJS.Закрыть();

ЧтениеJS = Новый ЧтениеJSON;
ЧтениеJS.УстановитьСтроку(СтрокаJS);
ТаблицаКопияJS = СериализаторXDTO.ПрочитатьJSON(ЧтениеJS);
ЧтениеJS.Закрыть();

Хочу обратить внимание на параметр НазначениеТипаXML.Явное в методе ЗаписатьJSON без кот
орого при чтении из строки будет выдаваться ошибка, либо надо будет при чтении указать тип объекта.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

   

2018г. Профессия — 1С. Обмен опытом по программированию в 1С