Оптимизировать код ОФ ЗАПРОС В ЦИКЛЕ!!!

1. Kaspirovsky 216 28.11.17 05:17 Сейчас в теме
ОФ 8,2 Как оптимизировать код? ЗАПРОС В ЦИКЛЕ!!!

Задача: У документа "ПриходнаяНакладная" при проведении алкогольной продукции ,если не заполнена колонка ТЧ.Состав - "Производитель" тогда запрет проведения.
Сделал обращение в РС "ВидыАлкогольнойПродукции" и получаеться ЗАПРОС В ЦИКЛЕ!!! как можно оптимизировать это?? чтобы не было запроса в цикле?

Я так сделал:
-В модуле док-та "ПриходнаяНакладная" в обработчике "ПередЗаписью" пишу

Для каждого Строка из Состав Цикл  		
		Если ПроверкаАлкогольнойПродукции(Строка.Номенклатура) Тогда	//обращение у функции
			Если Строка.Производитель.Пустая()  тогда 
				Сообщить("Документ не проведен, у номенклатуры с номером №" + Строка.НомерСтроки + Строка.Номенклатура +  ", не указан производитель!");
				Отказ = Истина;
				Возврат;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
Показать


и соответственно сама функция


Функция ПроверкаАлкогольнойПродукции(Номенклатура)
	
	Запрос = Новый Запрос;
	Запрос.Текст = 
		"ВЫБРАТЬ
		|	ВидыАлкогольнойПродукции.Номенклатура КАК Номенклатура
		|ИЗ
		|	РегистрСведений.ВидыАлкогольнойПродукции КАК ВидыАлкогольнойПродукции
		|ГДЕ
		|	ВидыАлкогольнойПродукции.Номенклатура = &Номенклатура";
	
	Запрос.УстановитьПараметр("Номенклатура", Номенклатура);
	
	РезультатЗапроса = Запрос.Выполнить();
	
	ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
	
	Если ВыборкаДетальныеЗаписи.Следующий() Тогда
		Возврат Истина 
	КонецЕсли;
	
	Возврат Ложь;
	КонецФункции
Показать
По теме из базы знаний
Ответы
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
2. TODD22 18 28.11.17 05:19 Сейчас в теме
Выгрузить колонку Номенклатура в массив.
Номенклатура = Состав.ВыгрузитьКолонку("Номенклатура");


И массив передать в запрос в качестве параметра.
То есть:
|	ВидыАлкогольнойПродукции.Номенклатура В (&Номенклатура)"; 


А дальше обработать результат запроса.
3. ben19791010 28.11.17 05:20 Сейчас в теме
ТЧ.Состав - "Производитель" тогда запрет проведения


т.е. у любой строки из ТЧ? тогда это полюбому перебор ТЧ...имхо но могу ошибаться,
я другого метода отсутствия параметра в ТЧ найти не знаю
4. TODD22 18 28.11.17 05:25 Сейчас в теме
РезультатЗапроса = Запрос.Выполнить(); 

ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать(); 

Если ВыборкаДетальныеЗаписи.Следующий() Тогда 
Возврат Истина 
КонецЕсли; 

Замени на:

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

Тебе выборку получать не надо если у тебя в результате запроса что то есть. Просто проверяй на пустоту результат.
5. TODD22 18 28.11.17 05:26 Сейчас в теме
Но правильно наверное обработать результат запроса и вывести пользователю сообщение и перечислить позиции номенклатуры.
6. TODD22 18 28.11.17 05:28 Сейчас в теме
Тогда так:
РезультатЗапроса = Запрос.Выполнить(); 
Если НЕ РезультатЗапроса.Пустой() Тогда
       Выборка = РезультатЗапроса.Выбрать()
       Пока Выборка.Следующий() Цикл
                Сообщить("У номенклатуры "+ Выборка.Номенклатура + " что то там не указано."); 
       КонецЦикла;
КонецЕсли; 
7. Kaspirovsky 216 28.11.17 05:38 Сейчас в теме
(6)
что то я может не догоняю, как будет результат запроса в цикле, так и остался...

Для каждого Строка из Состав Цикл  	//ВОТ цикл
		Если ПроверкаАлкогольнойПродукции(Строка.Номенклатура) Тогда	  //А здесь каждый раз проверка??
			Если Строка.Производитель.Пустая()  тогда 
				Сообщить("Документ не проведен, у номенклатуры с номером №" + Строка.НомерСтроки + Строка.Номенклатура +  ", не указан производитель!");
				Отказ = Истина;
				Возврат;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
Показать
8. TODD22 18 28.11.17 05:43 Сейчас в теме
(7)Так ты убери этот цикл. Выгрузи номенклатуру в массив, передай массив в запрос, полученный результат обработай. За тебя весь код написать?
9. Aitbay 28.11.17 05:46 Сейчас в теме
а не проще сначала выгрузить всю номенклатуру в таблицу значений а потом в цикле просто искать в этой таблице.
перед циклом делаем запрос выгружаем
Запрос = Новый Запрос; 
Запрос.Текст = 
"ВЫБРАТЬ 
|	ВидыАлкогольнойПродукции.Номенклатура КАК Номенклатура 
|ИЗ 
|	РегистрСведений.ВидыАлкогольнойПродукции КАК ВидыАлкогольнойПродукции";

РезультатЗапроса = Запрос.Выполнить().Выгрузить(); 

Для каждого Строка из Состав Цикл
Если РезультатЗапроса.Найти(Строка.Номенклатура, "Номенклатура") = Неопределено Тогда
Сообщить("Документ не проведен, у номенклатуры с номером №" + Строка.НомерСтроки + Строка.Номенклатура + ", не указан производитель!"); 
Отказ = Истина; 
Возврат; 
КонецЕсли
КонецЦикла
Показать
10. TODD22 18 28.11.17 05:49 Сейчас в теме
(9)
а не проще сначала выгрузить всю номенклатуру в таблицу значений

Проще, но выгружать результат запроса в таблицу значений без необходимости это не правильно.
11. TODD22 18 28.11.17 05:50 Сейчас в теме
(9)Так же как и не очень правильно получать запросом "весь" регистр, а потом результат выгружать в ТЗ по которой осуществляется поиск.
12. japopov 68 28.11.17 08:31 Сейчас в теме
А что такого сложного или неправильного?
1) Из всей табличной части выгружаем в таблицу значений со столбцами НомерСтроки и Номенклатура.
2) Делаем запрос, который в качестве параметра принимает нашу ТЗ, загружает во временную таблицу и индексирует по Номенклатуре.
3) Следующий запрос в том же пакете возьмёт временную таблицу и левым соединением проверит всё, что надо. На выходе получаем результат запроса со столбцом НомерСтроки, оставляя только ошибочные строки.
4) Выгружаем результат запроса в таблицу значений, оттуда выгружаем колонку НомерСтроки в массив, который скармливаем функции СтрСоединить(). Всё, у нас готова строка с перечислением ошибочных строк документа! А проверить, были ли ошибки вообще, просто: достаточно проверить не пустой ли результат запроса, или число строк в таблице значений.

Запрос выполнится на сервере, достаточно быстро и без лишних телодвижений.
13. TODD22 18 28.11.17 08:39 Сейчас в теме
(12)
или неправильного?

Не правильно выгружать результат запроса в ТЗ без необходимости, нужно пользоваться выборкой из результата запроса.
2) Делаем запрос, который в качестве параметра принимает нашу ТЗ, загружает во временную таблицу и индексирует по Номенклатуре.
3) Следующий запрос в том же пакете возьмёт временную таблицу и левым соединением проверит всё, что надо. На выходе получаем результат запроса со столбцом НомерСтроки, оставляя только ошибочные строки.

В данной задаче грузить ТЗ в результат запроса то же наверное избыточное действие. Там довольно простая проверка. Достаточно выгрузить в массив колонку с номенклатурой, передать в запрос как параметр и в запросе сделать проверку нужных условий.
14. japopov 68 28.11.17 08:44 Сейчас в теме
(13) Нет, IMHO, как раз тут - лучше ТЗ.
Ваш метод быстро даст ответ, все ли строки - с заполненным Производителем. Но он не даст ответа, в каких строках ошибка. Если бы не это, было бы проще: в параметр запроса передать массив номенклатуры, потом просто
Если ПроверочныйЗапрос.Выполнить().Выбрать().Следующий() Тогда
    //Сообщаем об ошибке
КонецЕсли;


Но нам нужно получить номера ошибочных строк! Именно поэтому нужно в запрос передавать и номера строк, и Номенклатуру, а возвращать - только номера строк с ошибками.
15. TODD22 18 28.11.17 08:50 Сейчас в теме
(14)Он даст ответ у какой номенклатуры не заполнено то что проверяется. Может вывести название номенклатуры будет достаточно.
К тому же можно обойти выборку в которой так же выводить номенклатуру и номер строки(если конечно его подгрузить предварительно в запрос).

а возвращать - только номера строк с ошибками.

Сообщить("Документ не проведен, у номенклатуры с номером №" + Строка.НомерСтроки + Строка.Номенклатура + ", не указан производитель!"); 

тут вроде как и номенклатура то же выводится.
16. japopov 68 28.11.17 08:57 Сейчас в теме
(15) Сравните Ваш подход и мой.
Ваш:
1) выгружаем колонку ТЧ в массив.
2) передаём в запрос массив номенклатуры, получаем результат.
3) делаем цикл, перебираем все строки ТЧ, чтобы убедиться, что всё нормально, или нет.
Попутно держим дополнительную переменную, куда записываем встреченные ошибки.
4) сообщаем пользователю.

Мой:
1) Выгружаем ТЧ в ТЗ.
2) передаём ТЗ в запрос, получаем результат.
3) Если результат пустой, то всё хорошо. Тогда не надо даже дальнейших действий делать!
4) Получаем результат, сворачиваем его в строчную переменную и сообщаем пользователю - всё это уложится в одну строку кода.

Мой алгоритм выполнится полностью на сервере, то есть быстрее, и потребует получение данных только в случае ошибки, то есть, отработает кратно быстрее при перепроведении заведомо корректных документов.
17. TODD22 18 28.11.17 09:02 Сейчас в теме
(16)У него ОФ.
Мой вариант так же выполняется на сервере. В результате запроса будет только та номенклатура которая не отвечает условиям. По этому что вы там приписали 3 пунктом мимо.
18. japopov 68 28.11.17 09:06 Сейчас в теме
(17)
Ваш алгоритм подразумевает обход циклом, который делается ВСЕГДА, и НА КЛИЕНТЕ (не забывайте, у автора обычное приложение)! То есть, данные ВСЕГДА гоняются между клиентом и сервером.
Мой алгоритм выполняется ТОЛЬКО НА СЕРВЕРЕ, а на клиент данные нужно передавать ТОЛЬКО при ошибке, и ТОЛЬКО те, которые нужно сообщить, а не всю табличную часть.
Разницу Вы, вероятно, не видите, да?

Ваш бы пыл, да в рациональное русло...
19. TODD22 18 28.11.17 09:12 Сейчас в теме
(18)Вы не поняли что я написал, но уже что то на фантазировали какие то циклы, передачу данных.
Ваш бы пыл, да в рациональное русло...

Это вообще к чему?
20. japopov 68 28.11.17 09:20 Сейчас в теме
(19)
Вы написали: передавать в запрос массив номенклатуры.

Автору надо:
а) быстро ответить на вопрос, есть ли ошибки;
б) если ошибки есть, вывести пользователю номера строк с ошибками.

Для того, чтобы выполнить задачу автора, в Вашем случае придётся обходить результат запроса в цикле. Для этого на клиент надо будет передать результат запроса и табличную часть документа. В случае массового перепроведения это станет проблемой. Да, и в Вашем случае можно модифицировать запрос, чтобы в случае, когда всё хорошо, не перебирать все строки. Но от цикла при ошибках, а значит, и от передачи лишних данных от клиента в сервер и обратно, Вы не обойдётесь.
А ведь задача-то решается примитивно! Хватит уже троллить!
21. TODD22 18 28.11.17 09:45 Сейчас в теме
(20)
в Вашем случае придётся обходить результат запроса в цикле.

А что это какая то проблема? Если в результате запроса несколько элементов их логично надо обходить в цикле, это же не запрос в цикле, а работа с уже прочитанными данными.

Если ПроверочныйЗапрос.Выполнить().Выбрать().Следующий() Тогда
    //Сообщаем об ошибке
КонецЕсли;

Вы считаете проверять пустой запрос выборкой это правильно?

Для этого на клиент надо будет передать результат запроса и табличную часть документа.

Зачем?

Но от цикла при ошибках, а значит, и от передачи лишних данных от клиента в сервер и обратно, Вы не обойдётесь.

Так вы и так при ошибках должны передать данные что бы вывести сообщение пользователю.

Хватит уже троллить!

Перестаньте уже делать эти выпады... Не интересует дискуссия можете просто пройти мимо.
Оставьте свое сообщение

Для получения уведомлений об ответах подключите телеграм бот:
Инфостарт бот