Мина замедленного действия в методе 1С8 «НайтиСтроки», и ... разминирование.

14.02.12

Разработка - Механизмы платформы 1С

В этой статье рассматривается небезопасная фича метода НайтиСтроки в 1с8 и описывается способ, позволяющий сделать вызов этого метода надежным.

Скачать исходный код

Наименование Файл Версия Размер
down.zip
.zip 5,01Kb
16
.zip 5,01Kb 16 Скачать

Немногие знают, что метод НайтиСтроки в 1С работает не всегда ожидаемым образом.

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

Поэтому рекомендую добавить в глобальный модуль две функции НайтиСтроки и ПослеНайтиСтроки и вызывать вместо  М = ТЗ.НайтиСтроки(Структура) метод М = НайтиСтроки(ТЗ, Структура). Или последовательность: М= ТЗ.НайтиСтроки(Структура);  ПослеНайтиСтроки(М, ТЗ);

Параметр ТЗ во второй метод передается для совместимости с 1с80, где нет функции Владелец() у строки табличной части.

 

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

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

Функция НайтиСтроки(ТЗ, Структура) Экспорт
    
    М = ТЗ.НайтиСтроки(Структура);
    ПослеНайтиСтроки(М, ТЗ);
    
КонецФункции

Процедура ПослеНайтиСтроки(М, ТЗ = Неопределено) Экспорт
    
    Если М.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;
    
    //Для совместимости с 1с80
    Если ТЗ = Неопределено Тогда
        ТЗ = М[0].Владелец();
    КонецЕсли;
    
    ТЗ2 = Новый ТаблицаЗначений();
    ТЗ2.Колонки.Добавить("Индекс");
    ТЗ2.Колонки.Добавить("Строка");
    
    Для Каждого Эл ИЗ М Цикл
        НСтр = ТЗ2.Добавить();
        НСтр.Индекс = ТЗ.Индекс(Эл);
        НСтр.Строка = Эл;
    КонецЦикла;
    
    ТЗ2.Сортировать("Индекс");
    М.Очистить();
    Для Каждого Стр2 ИЗ ТЗ2 Цикл
        М.Добавить(Стр2.Строка);
    КонецЦикла;
    
КонецПроцедуры

В приложенной обработке формируется массив строк, потом случайным образом перетасовывается, что эмулирует фичу метода НайтиСтроки, после чего порядок восстанавливается вызовом ПослеНайтиСтроки.

См. также

Сервисы интеграции без Шины и интеграции

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Пример использования «Сервисов интеграции» без подключения к Шине и без обменов.

13.03.2024    2568    dsdred    16    

59

Поинтегрируем: сервисы интеграции – новый стандарт или просто коннектор?

Обмен между базами 1C Администрирование СУБД Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

В платформе 8.3.17 появился замечательный механизм «Сервисы интеграции». Многие считают, что это просто коннектор 1С:Шины. Так ли это?

11.03.2024    5926    dsdred    55    

83

Как готовить и есть массивы

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Все мы используем массивы в своем коде. Это один из первых объектов, который дают ученикам при прохождении обучения программированию. Но умеем ли мы ими пользоваться? В этой статье я хочу показать все методы массива, а также некоторые фишки в работе с массивами.

24.01.2024    5878    YA_418728146    25    

68

Планы обмена VS История данных

Обмен между базами 1C Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Вы все еще регистрируете изменения только на Планах обмена и Регистрах сведений?

11.12.2023    6981    dsdred    36    

113

1С-ная магия

Механизмы платформы 1С Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    19077    SeiOkami    46    

118

Дефрагментация и реиндексация после перехода на платформу 8.3.22

Механизмы платформы 1С Платформа 1С v8.3 Бесплатно (free)

Начиная с версии платформы 8.3.22 1С снимает стандартные блокировки БД на уровне страниц. Делаем рабочий скрипт, как раньше.

14.09.2023    12786    human_new    27    

76

Валидация JSON через XDTO (включая массивы)

WEB-интеграция Универсальные функции Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

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

28.08.2023    9410    YA_418728146    6    

143

Внешние компоненты Native API на языке Rust - Просто!

Механизмы платформы 1С Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Внешние компоненты для 1С можно разработывать очень просто, пользуясь всеми преимуществами языка Rust - от безопасности и кроссплатформенности до удобного менеджера библиотек.

20.08.2023    6530    sebekerga    54    

95
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
99. AlexO 135 11.12.14 10:34 Сейчас в теме
(98) тем не менее, именно в комментариях писали и продолжают писать (уже после множества "тема уже достаточно раскрыта") о том, что либо "проблема не существует", либо "да тут все просто, я сто раз уже так делал".
100. fixin 4253 11.12.14 13:42 Сейчас в теме
102. amiralnar 9 13.02.15 16:31 Сейчас в теме
Проблема действительно встречается.
Помня про эту статью и дискуссии, избежал ряда ошибок, лишний раз не полагаясь на сортировку, которой нет.
Данное решение не применял, но признаю практическую ценность статьи.
105. AlexO 135 02.03.12 16:14 Сейчас в теме
(0)
Программист предполагает, что после вызова метода строки в нем будут расположены в таком же порядке, как в исходной таблице значений. Но 1С это не гарантирует.

В общем-то, никто - ни Оракл, ни SQL, - не гарантируют расположение строк в выборке аналогично сорс-таблице. И честно об этом предупреждают. SQL даже идет дальше - предупреждает, что и обратное - соответствие порядка в записываемом наборе строк их физическому расположению при записи в базу, - нисколько не гарантирует.
И только 1с не считает нужным прозрачно все описывать (или не знает реальное положение дел), что дает повод писать статьи )).
Надеюсь, в будущих релизах 1С будет гарантировать правильный порядок строк,

и как же они смогут ГАРАНТИРОВАТЬ аналогичный порядок записей? каким механизмом?
Сергей, вы в статье описываете метод найти индекс в сорс-таблице, и присвоить этот же индекс в таргет-таблице (найдя поиском элемент), ежели такой элемент попал в таргет отбором.
А потом отсортировать таргет по индексу "а вот былО так".
Вам же предлагают проиндексировать сорс-таблицу, получить таргет (с индексами из сорс-таблицы) и отсортировать её по индексу.
Т.е. что быстрей - зависит от размеров таблицы. Но оброаботка полученных данных на1с-сервере перекроет любые временные "преимущества", полученные на данном первоначальном этапе выборки.
106. hydro2588_2015 14 27.12.18 11:56 Сейчас в теме
А вот под новый год и у меня случилось "чудо", напоролся на эти грабли. Решил таким образом:
Процедура ПроверитьСортировкуМассива(МассивСоСтрокамиТЗ, ТЗ)
	СписокДляСортировки = Новый СписокЗначений;
	ТекущийИндекс = -1;
	НадоСортировать = Ложь;
	Для Каждого ЭлементМассива Из МассивСоСтрокамиТЗ Цикл
		ИндексТЗ = ТЗ.Индекс(ЭлементМассива);
		Если ТекущийИндекс > ИндексТЗ Тогда
			НадоСортировать = Истина;
		КонецЕсли;
		ТекущийИндекс = ИндексТЗ;
		СписокДляСортировки.Добавить(ЭлементМассива, ИндексТЗ)
	КонецЦикла;
	Если НадоСортировать Тогда
		СписокДляСортировки.СортироватьПоПредставлению();
		МассивСоСтрокамиТЗ = СписокДляСортировки.ВыгрузитьЗначения();
	КонецЕсли;
КонецПроцедуры
Показать
107. Franchiser 47 07.12.19 01:18 Сейчас в теме
(106) если указать Индекс как представление для СЗ, то будет выполнено преобразование к строке, и сортировка такого списка будет выполнена по правилу сортировки строк, т.е. будет порядок 1,10,2,3,30,31,4,5 и т.д.
108. Franchiser 47 07.12.19 10:24 Сейчас в теме
(0) проблема сейчас актуально, удалось добиться воспроизведения? По идее если без индексирования из, найтистроки() должно работать перебором строк и ошибки не должно быть.
109. Zerba 21.10.20 15:19 Сейчас в теме
В типовой КА 2.4 (довольно свежая конфа 2.4.12) в общем модуле ПродажиСервер, в процедуре ЗаполнитьРеализацииИЦены(...) данный сабж присутствует во всей красе

...
		|УПОРЯДОЧИТЬ ПО
		|	ЭтоВозвратнаяТара ВОЗР,
		|	ДатаРеализации УБЫВ,
		|	ДатаПередачиТары ВОЗР";
...
...
	РезультатЗапроса = Запрос.Выполнить().Выгрузить();
	Для Каждого СтрокаТовары Из ТабличнаяЧастьВозврата Цикл
		
		СтруктураОтбора = Новый Структура;
		СтруктураОтбора.Вставить("Номенклатура", СтрокаТовары.Номенклатура);
		СтруктураОтбора.Вставить("Характеристика", СтрокаТовары.Характеристика);
		СтруктураОтбора.Вставить("Серия", СтрокаТовары.Серия);
		СтруктураОтбора.Вставить("Назначение", СтрокаТовары.Назначение);
		
		НайденныеСтроки = РезультатЗапроса.НайтиСтроки(СтруктураОтбора);
		
		Для каждого НайденнаяСтрока Из НайденныеСтроки Цикл
			Если СтрокаТовары.Количество <= НайденнаяСтрока.Количество Тогда
...
Показать
110. DrBlack 23 21.10.20 15:46 Сейчас в теме
Очень много текста, не осилил, решена проблема или нет, но вот на всякий случай:
#Если _ Тогда
	ДокСсылка     = Документы.РасходнаяНакладная.ПустаяСсылка();
	НоменклСсылка = Справочники.Номенклатура.ПустаяСсылка();
#КонецЕсли

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	РасходнаяНакладнаяЗапасы.НомерСтроки КАК НомерСтроки,
|	РасходнаяНакладнаяЗапасы.Номенклатура КАК Номенклатура
|ИЗ
|	Документ.РасходнаяНакладная.Запасы КАК РасходнаяНакладнаяЗапасы
|ГДЕ
|	РасходнаяНакладнаяЗапасы.Ссылка = &ДокСсылка
|
|УПОРЯДОЧИТЬ ПО
|	НомерСтроки";
Запрос.УстановитьПараметр("ДокСсылка", ДокСсылка);

Результат = Запрос.Выполнить();
Если Результат.Пустой() Тогда
	Возврат;
КонецЕсли;

ТЗ = Результат.Выгрузить();

НайдСтроки = ТЗ.НайтиСтроки(Новый Структура("Номенклатура", НоменклСсылка));

ТЗ_Буф = ТЗ.Скопировать(НайдСтроки);
ТЗ_Буф.Сортировать("НомерСтроки Возр");
Показать
111. SlavaKron 21.10.20 15:59 Сейчас в теме
(110) Во-первых, Скопировать можно сразу с отбором. Во-вторых, это не решение, потому что результатом должен быть массив строк искомой таблицы значений.
112. DrBlack 23 21.10.20 16:05 Сейчас в теме
(111)
Во-первых, Скопировать можно сразу с отбором.

Согласен, но это не критично, так легло просто :)

(111)
Во-вторых, это не решение, потому что результатом должен быть массив строк искомой таблицы значений

Без проблем, ещё четыре строчки дописать:
МассивСтрок = Новый Массив;
Для Каждого ТекСтр Из ТЗ_Буф Цикл
    МассивСтрок.Добавить(ТекСтр);
КонецЦикла;
113. SlavaKron 21.10.20 16:33 Сейчас в теме
(112) ТекСтр это не строка искомой ТЗ. Да и проблема не в реализации как таковой, а в том, что любое решение значительно увеличивает время работы алгоритма.
114. ImHunter 315 21.10.20 17:18 Сейчас в теме
Недавно бодался с 1С - тоже про НайтиСтроки. Но про поиск в ТЧ объекта.
Так вот, при поиске, включающем поле НомерСтроки, отбор по номеру строки игнорируется.

После долгой переписки, 1Сы признали, что ошибка имеет место. Но когда исправят - неизвестно.
115. FatPanzer 21.10.20 17:22 Сейчас в теме
(114)
Так вот, при поиске, включающем поле НомерСтроки, отбор по номеру строки игнорируется.
И это логично, поскольку номер строки никакого отношения к реальным данным строки не имеет и не является её неотъемлемой частью. Да и прикладного смысла в этом нет никакого - в отборе НайтиСтроки() можно использовать только операции сравнения, соответственно, больше одной записи в отборе вы не сможете получить. Поэтому гораздо проще получить строку в ТЧ по её индексу, который всегда равен (НомерСтроки-1).
116. ImHunter 315 21.10.20 17:30 Сейчас в теме
(115) Для меня - нелогично. Ведь это поле вполне себе выгружается в ТЗ. Т.е., как бы, оно настоящее.
Насчет прикладного смысла - ну... есть все же такой прикладной смысл. Иначе бы это и не обнаружилось.
Причем, при поиске в упр.форме по отражению ТЧ, такой поиск нормально работает.
117. FatPanzer 21.10.20 17:36 Сейчас в теме
(116) Нет, не настоящее. Было бы оно настоящим - оно бы перемещалось вместе со строкой при её перемещении. Это просто уникальное автоматическое поле для обеспечения ключа при записи движений в регистры.

А в ТЗ оно выгружается только в целях возможности восстановления порядка строки при обратной загрузке.
Например, после выгрузки в ТЗ её можно пересортировывать для удобства обработки (пропорционального распределения, хронологической обработке по колонке дата и прочее), а перед обратной загрузкой в ТЧ - восстановить исходный порядок строк, отсортировав ТЗ по НомеруСтроки...
Вот и все её прикладное назначение.
118. ImHunter 315 22.10.20 06:11 Сейчас в теме
(117) Да блин) Знаю я, что это поле ненастоящее. Но это никак не декларируется в документации. В обычных сценариях работы с данными, это поле ведет себя тоже, как обычное поле. Поэтому ожидаю предсказуемого (обычного) результата при выполнении НайтиСтроки().
Если уж нельзя искать по этому полю, так напишите про это в СП/ИТС, как про фичу... Делов-то.
119. fixin 4253 22.10.20 11:39 Сейчас в теме
(118) ну по номеру строки как сказали выше, искать нет смысла. Проще сразу получить строку по индексу. ;-)
120. ImHunter 315 22.10.20 12:27 Сейчас в теме
(119) Ну...) Есть в этом смысл или нет - мне виднее для моей прикладной задачи. Я, конечно, обошел найденный глюк. Но решил таки выяснить в 1С, что они скажут по этому поводу.
121. dehro 5 23.10.20 15:11 Сейчас в теме
Проблему не понял.
Для чего нужен упорядоченный массив строк некой таблицы придумать не смог.

Но даже при таком раскладе алгоритм плох. Автор заводит новую ТаблицуЗначений (!), ищет строки в материнской ТаблицеЗначений (пусть по индексу, но всё-таки). Куча циклов, условий....

Автору нужно в школу, по моему.
122. SlavaKron 23.10.20 15:26 Сейчас в теме
(121)
Для чего нужен упорядоченный массив строк некой таблицы придумать не смог.

Например, для получения остатков по партиям в отсутствии партионного учета, когда восстанавливается картина списаний по партиям.
123. dehro 5 23.10.20 16:10 Сейчас в теме
(122)
КолВо = М.Количество() -1;
	
	Для й = 0 по КолВо - 1 цикл
		Для жи = й+1 по КолВо цикл
			Если ТЗ.Индекс(М[й]) > ТЗ.Индекс(М[жи]) тогда  //Туточки прописать условие сравнения строк, ведь не обязательно это индекс, в остатке по датам, наверное, дата прихода партии 
				ПеременнаяОбмена =  М[й];
				М[й] =  М[жи];
				М[жи] = ПеременнаяОбмена;
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
Показать
124. SlavaKron 23.10.20 16:24 Сейчас в теме
(123) В вашем примере я ничего не понял. С партиями, наверно, неудачный пример. Давайте такое: в отчете, который выводит движения товара, необходимо для каждой строки движения знать розничную цену, актуальную на дату движения. Некоторые отправят меня решать это в запросе, но по мне это стрельба из пушки по воробьям.
125. dehro 5 23.10.20 16:30 Сейчас в теме
Если это отчет: данные для отчета однозначно получены запросом. Добавить в пакет - дело несложное.

Тем более автор не пишет про поиск, он пишет про сортировку. А я привёл пример сортировки в массиве без (!) дополнительных массивов, ТЗ, etc.
Мало того, мой пример универсальней: можно написать процедуру, в параметрах указать по какому столбцу сортировать.
Оставьте свое сообщение