Всем привет! Пытаюсь создать свою первую внешнюю обработку, мне надо сделать так:
пробежаться по всему списку номенклатуры, если на номенклатуру нет никаких ссылок или есть только ссылки на установку цен, то пометить эту номенклатуру на удаление удаление и все.
Вот что написал:
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| Номенклатура.Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| НЕ Номенклатура.ЭтоГруппа
|
|УПОРЯДОЧИТЬ ПО
| Номенклатура.Наименование";
РезультатЗапроса = Запрос.Выполнить().Выбрать();
(1) LastSoldier, Если надо удалить то можно воспользоваться Пометка на удаление неиспользуемых элементов справочников и документов http://infostart.ru/public/65132/ там же можно посмотреть как...
Если "поучиться самому" - то в чем смысл приведенного кода? (в чём вопрос)
34.
tsmgeorg@gmail.com
26.01.15 12:07 Сейчас в теме
(1) LastSoldier,
Если хотите выборочно, вот пример. Весь массив ссылок справочника если поместить в параметр функции найтипоссылкам(МассивОбъектов) будет очень долго искать. А в данном примере можно хоть отследить
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| ДоговорыКонтрагентов.Ссылка
|ИЗ
| Справочник.ДоговорыКонтрагентов КАК ДоговорыКонтрагентов
|ГДЕ
| ДоговорыКонтрагентов.ПометкаУдаления = ИСТИНА";
РезультатЗапроса = Запрос.Выполнить();
Сообщение = Новый СообщениеПользователю;
Если Не РезультатЗапроса.Пустой() Тогда
ВыборкаЗапроса = РезультатЗапроса.Выбрать();
Пока ВыборкаЗапроса.Следующий() Цикл
МассивОбъектов = Новый Массив;
МассивОбъектов.Добавить(ВыборкаЗапроса.Ссылка);
ТЗСсылок = НайтиПоСсылкам(МассивОбъектов);
Если ТЗСсылок.Количество() = 0 Тогда
СправочникОбъект = ВыборкаЗапроса.Ссылка.ПолучитьОбъект();
Сообщение.Текст = "Удален договор" + СокрЛП(ВыборкаЗапроса.Ссылка);
Сообщение.Сообщить();
СправочникОбъект.Удалить();
КонецЕсли;
КонецЦикла;
КонецЕсли;
(52) AlexO, Если Вам такая обработка нужна, то могу и выложить ее. Она только помечает номенклатуру на удаление и все. С пустыми ссылками или с теми что ниже описанны, остальные не трогает
Если (ДРегистры="Установка цен номенклатуры")
или (ДРегистры="Группы значений доступа")
или (ДРегистры="(не используется) Группы значений доступа") Тогда
1. Получить запросом список номенклатуры как у тебя в сабже.
2. НайтиПоСсылкам(<СписокСсылок>);
3. Пройтись по результату п.2, в случае если удовлетворяют твоим условиям - пометить на удаление
НайтиПоСсылкам (< Список ссылок> )
Параметры:
<Список ссылок> Обязательный
Тип: Массив. Массив со списком ссылок на объекты, ссылки на которые нужно найти.
Возвращаемое значение:
Тип: ТаблицаЗначений. Таблица значений, состоящая из колонок с индексами: 0 - Искомая ссылка; 1 - Ссылка на объект, который содержит искомую ссылку.
Описание:
Осуществляет поиск ссылок на объекты.
Я смотрел этот пример
Ссылки = НайтиПомеченныеНаУдаление();
ТабСсылок = НайтиПоСсылкам(Ссылки);
Мне не надо искать помеченные на удаление, тем более все подряд. вот я и не могу понять как ему указать что надо искать только "номенклатуру" и не всю подряд, а сначала номенклатуру №1 и все ее ссылки, потом номенклатуру № 2 и все ее ссылки и тд.
Это моя первая обработка, я много не знаю.
Напишите пример если не трудно, ну там о партнерах, чтобы понять хоть суть
Пока РезультатЗапроса.Следующий() Цикл
МассивСсылок = Новый Массив;
МассивСсылок.Добавить(РезультатЗапроса.Ссылка);
ТабСсылок = НайтиПоСсылкам(МассивСсылок);
Если ТабСсылок.Количество() >0 тогда
// Ссылки есть,
иначе
// нихрена нету, обрабатываем
КонецЕсли;
КонецЦикла;
(10) Boneman, Только надо не добавлять в массив значения, а переназначать первый
МассивСсылок = Новый Массив(1);
Пока РезультатЗапроса.Следующий() Цикл
МассивСсылок[0] = РезультатЗапроса.Ссылка;
ТабСсылок = НайтиПоСсылкам(МассивСсылок);
Если ТабСсылок.Количество() >0 тогда
// Ссылки есть,
иначе
// нихрена нету, обрабатываем
КонецЕсли;
КонецЦикла;
Показать
Иначе он будет каждый раз увеличивать массив и следовательно потом будет искать по большому массиву. Вроде так.
(10) огромное спасибо. Теперь я понял как это делается. Дальше буду смотреть что надо отбирать, думаю тут пока справлю, о результате обязательно отпишусь.
Скажите, в 1с есть такое, чтобы когда я проверяю мою обработку(Начать отладку), не закрывать постоянно 1с
(14) LastSoldier, Чтобы не закрывать/открывать обработку сделай на форме кнопку "Перезагрузить" а в модуле формы Процедуру для кнопки:
Процедура КоманднаяПанель1Перезагрузка(Кнопка)
Для каждого МетаФорма Из ЭтаФорма.Метаданные().Формы Цикл
ТекФорма = ПолучитьФорму(МетаФорма);
Если ТекФорма.Открыта() Тогда
ТекФорма.Закрыть();
Если ТекФорма = ЭтаФорма Тогда
Если Найти(Строка(ТипЗнч(ЭтотОбъект)), "Внешняя обработка объект:") = 1 Тогда
ВнешниеОбработки.Создать(ЭтотОбъект.ИспользуемоеИмяФайла).ПолучитьФорму(МетаФорма.Имя).Открыть();
Иначе
ВнешниеОтчеты.Создать(ЭтотОбъект.ИспользуемоеИмяФайла).ПолучитьФорму(МетаФорма.Имя).Открыть();
КонецЕсли;
КонецЕсли;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Показать
Код взят на Инфостарте, найди автора и передай ему спасибо :)))
Вот что получилось, вроде работает, только еще не все условия учел
Оцените и скажите замечания.
Проблема что очень долго все обрабатывает
&НаСервере
Процедура ВыполнитьИзменениеНаСервере()
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| Номенклатура.Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| НЕ Номенклатура.ЭтоГруппа
|
|УПОРЯДОЧИТЬ ПО
| Номенклатура.Наименование";
РезультатЗапроса = Запрос.Выполнить().Выбрать();
Пока РезультатЗапроса.Следующий() Цикл
Элемент = РезультатЗапроса.Ссылка.ПолучитьОбъект();
МассивСсылок = Новый Массив;
МассивСсылок.Добавить(РезультатЗапроса.Ссылка);
ТабСсылок = НайтиПоСсылкам(МассивСсылок);
Если ТабСсылок.Количество() >0 тогда
Сч=ТабСсылок.Количество() - 1;
Пока Сч>=0 Цикл
ДРегистры=ТабСсылок.Получить(Сч).Метаданные.Синоним;
Если (ДРегистры="Установка цен номенклатуры")
или (ДРегистры="Группы значений доступа")
или (ДРегистры="(не используется) Группы значений доступа") Тогда
Сч=Сч-1;
Иначе
Прервать;
КонецЕсли;
Если Сч=0 Тогда
Элемент.ПометкаУдаления = Истина;
Элемент.Записать();
КонецЕсли;
КонецЦикла;
Иначе
Элемент.ПометкаУдаления = Истина;
Элемент.Записать();
КонецЕсли;
КонецЦикла;
КонецПроцедуры
(18) LastSoldier, так как я любитель модульного программирования то вынес бы пометку на удаление в отдельную процедуру. Передавая туда ссылку на объект:
(23) dj_serega, а скажите, чем это лучше, вынести в отдельный модуль и "ПометкаУдаления = Истина" я бы заменил на "УстановитьПометкуУдаления(Истина)"???
Это ускоряет работу обработки или чем оно помогает?
Мне как начинающему, это не понят. Поясните пожалуйста в кратце
А можно как-то эту часть ускорить?
(24) LastSoldier, так писал уже в (21) - отрабатывай пакетом
Пока РезультатЗапроса.Следующий() Цикл
МассивСсылок = Новый Массив;
МассивСсылок.Добавить(РезультатЗапроса.Ссылка);
Элементов = 1;
Пока РезультатЗапроса.Следующий() Цикл
Элементов = Элементов + 1
МассивСсылок.Добавить(РезультатЗапроса.Ссылка);
Если Элементов = 999 Тогда
Прервать;
КонецЕсли;
КонецЦикла;
ТабСсылок = НайтиПоСсылкам(МассивСсылок);
// обрабатывай ТЗ ТабСсылок
КонецЦикла;
Показать
НайтиПоСсылкам(МассивСсылок) для 1000 ссылок будет работать по времени как для 1й
(25) caponid, я сегодня если успею или завтра попробую этот вариант и обязательно Вам отпишусь, не пропадайте далеко )
Я просто подумал может еще кто что-то подскажет
(25) caponid, а подскажи, как теперь надо двигаться по массиву.
Я вот сделал "Для каждого Элем ИЗ МассивСсылок цикл", а как должен выглядеть второй цикл который будет двигать только по ссылкам этого элемента?
Пока еще сам не понял
(25) caponid, а как в цикле это теперь все отрабатывать? пока ничего не получается. Мне же тут надо одним циклом обходить элементы, а другим ссылки на эти элементы. Вот как сделать эти циклы так и не пойму, двигаться по элемента еще понятно "Для каждого Элем ИЗ МассивСсылок цикл", а как теперь двигаться по ссылкам этого элемента и как указывать ссылки для следующего элемента?
(24) LastSoldier,
1. Если какой-то код используется 2 раза, то его, логично вынести в отдельную процедуру/функцию. И если нужно будет "допилять" 1 строку, то её нужно будет "допиливать" в одном месте (а не 2х, 3х, и тд).
Согласен что для одной обработки это не актуально, но выработав привычку так писать, будет проще в будущем :)
К примеру если нужно во всех формах объектаов (их 150), ПриСозданииНаСервере, установить ТолькоПросмотр если нет роли Бухгалтер. Можно написать "ТолькоПросмотр = Не РольДоступна("Бухгалтер")". А если нужно потом добавить првоерку на "ПолныеПрава"? Придется менять все объекты, а если вызывать общую процедуру то придется менять только в одном месте :)
2. У "Пометка = Истина" и "УстановитьПометкуУдаления()" разницы между собой практически нет. И в первом и во втором случае выполняется пометка на удаление. Какая же между ними разница почитайте в СП :)
(27) dj_serega, 1 Я Вас понял, действительно в дальнейшем мне это очень поможет, Спасибо
2 Прочитал, прочитал, очень полезно )
(25) caponid, Это получится намного лучше обрабатывать сразу кучу товара. А скажите, сколько строк можно загонять в массив чтобы все работало корректно?
1000 товара и всех их ссылки, это будет не многовато?
МассивСсылок = Новый Массив;
МассивСсылок.Добавить(РезультатЗапроса.Ссылка);
ТабСсылок = НайтиПоСсылкам(МассивСсылок);
можно еще добавить - обрабатывать не по 1й ссылке, а пакетом по допустим по 1000 ссылок - время работы функции НайтиПоСсылкам увеличется незначительно, но сразу отработает 1000 ссылок.
можно замерить скорость поиска 1й ссылки и 1000 - думаю там будут расхождения в 10ки секунд всего
(31) Это получается что нам надо взять 1 элемент из МассивСсылок, сравнить с элементами ТабСсылок и если есть ссылки, то записать эти данные в Таблицу3? ну а если нет ссылок, то сразу пометить на удаление.
А по второму <ИсключитьОбъекты> "Установка цен номенклатуры"
"Группы значений доступа")
"(не используется) Группы значений доступа"
Это и будут мои исключения?
Тип: Массив.
В качестве элементов массива могут выступать:
Объект метаданных,
Строка – полное имя объекта метаданных.
Свойство позволяет явно указать объекты метаданных, которые следует исключить из области поиска ссылок на объекты.
Допустимые значения:
Неопределено
Пустой массив (нет объектов, которые необходимо дополнительно включить в область поиска).
Массив объектов метаданных.
т.е надо написать
МассивИскл = Новый Массив;
//если строкой
МассивИскл.Добавить("РегистрыСведений.ИсключаемыйРегистр");
МассивИскл.Добавить("Справочники.ИсключаемыйСправочник");
//или по метаданным
МассивИскл.Добавить(Метаданные.РегистрыСведений.Найти("ИсключаемыйРегистр");
...
МассивИскл = Новый Массив;
МассивИскл.Добавить(Метаданные.Документы.Найти("УстановкаЦенНоменклатуры"));
МассивИскл.Добавить(Метаданные.РегистрыСведений.Найти("ГруппыЗначенийДоступа"));
МассивИскл.Добавить(Метаданные.РегистрыСведений.Найти("УдалитьГруппыЗначенийДоступа"));
ТабСсылок = НайтиПоСсылкам(МассивЭлементов,,,МассивИскл);
Та же самая ошибка
{Форма.Форма.Форма(36)}: Ошибка при вызове метода контекста (НайтиПоСсылкам)
ТабСсылок = НайтиПоСсылкам(МассивЭлементов,,,МассивИскл);
по причине:
Несоответствие типов (параметр номер '4')
И так то же
МассивИскл = Новый Массив;
МассивИскл.Добавить("РегистрыСведений.ГруппыЗначенийДоступа");
МассивИскл.Добавить("РегистрыСведений.УдалитьГруппыЗначенийДоступа");
МассивИскл.Добавить("Документы.УстановкаЦенНоменклатуры");
ТабСсылок = НайтиПоСсылкам(МассивЭлементов,,,МассивИскл);
(33) caponid, А что мы вообще там собрались исключать НайтиПоСсылкам(МассивСсылок)? мы же должны пройти все элементы массива
Чет то что Вы описали пока сложно для меня
Вот сделал, для всей базы еще не проверял, но работает в сотню раз быстрее )
Процедура ВыполнитьИзменениеНаСервере()
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| Номенклатура.Ссылка
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| НЕ Номенклатура.ЭтоГруппа
|
|УПОРЯДОЧИТЬ ПО
| Номенклатура.Наименование";
РезультатЗапроса = Запрос.Выполнить().Выбрать();
Пока РезультатЗапроса.Следующий() Цикл
МассивЭлементов = Новый Массив;
МассивЭлементов.Добавить(РезультатЗапроса.Ссылка);
Элементов=1;
Пока РезультатЗапроса.Следующий() Цикл
Элементов = Элементов + 1;
МассивЭлементов.Добавить(РезультатЗапроса.Ссылка);
Если Элементов = 500 Тогда
Элементов=1;
Прервать;
КонецЕсли;
КонецЦикла;
ТабСсылок = НайтиПоСсылкам(МассивЭлементов);
Если ТабСсылок.Количество() >0 тогда
Сч=ТабСсылок.Количество() - 1;
Пока Сч>=0 Цикл
ДРегистры=ТабСсылок.Получить(Сч).Метаданные.Синоним;
Если (ДРегистры="Установка цен номенклатуры")
или (ДРегистры="Группы значений доступа")
или (ДРегистры="(не используется) Группы значений доступа") Тогда
ТабСсылок.Удалить(Сч);
Сч=Сч-1;
Иначе
Сч=Сч-1;
КонецЕсли;
КонецЦикла;
КонецЕсли;
ТабСсылок.Свернуть("Ссылка");
СчМ=МассивЭлементов.Количество() - 1;
Пока СчМ>=0 Цикл
СтрокаСРМ=МассивЭлементов.Получить(СчМ).Наименование;
СчТ=ТабСсылок.Количество() - 1;
Пока СчТ>=0 Цикл
СтрокаСРТ=ТабСсылок.Получить(СчТ).Ссылка.Наименование;
Если СтрокаСРМ=СтрокаСРТ Тогда
Прервать;
Иначе
СчТ=СчТ-1;
КонецЕсли;
Если СчТ=-1 Тогда
ВыполнитьПометкуУдаления(МассивЭлементов[СчМ].Ссылка);
КонецЕсли;
КонецЦикла;
СчМ=СчМ-1;
КонецЦикла;
КонецЦикла;
КонецПроцедуры;
Подскажите еще такую вещь, в чем разница и что лучше между
1)Удаление неиспользуемых элементов справочников
и
2)Удаление помеченных объектов.
Просто после того как я прошелся обработкой которая пометила 10к товара на удаление, я использовал первый метод (он намного быстрее), но он удалил не 10к товара, а 10 043, откуда еще взялись эти 43???
А "Удаление помеченных объектов" удаляет 10к, ну оччччеееень долго.
Можно было все на самом деле сделать гораздо проще)) - есть стандартная процедура УдалитьОбъекты()
//МассивСсылок.Добавить(Выборка.Ссылка);
//массив ссылок на удаление
НайденныеДанные = Новый ТаблицаЗначений; // вернет тз того, что не смог удалить
ОбластьПоиска = Новый Массив; // пустой массив - так нужно:)
ИсключитьОбъекты = Новый Массив; // по этим объектам проверки на ссылочную целостность не будет
ИсключитьОбъекты.Добавить(Метаданные.РегистрыСведений.РегистрЧегоТоТам);
УстановитьМонопольныйРежим(Истина);
УдалитьОбъекты(МассивСсылок, Истина, НайденныеДанные, ОбластьПоиска, , ИсключитьОбъекты);
УстановитьМонопольныйРежим(Ложь);
(47) caponid, ну я просто поставил галочку только у номенклатуры, поэтому у меня и возник такой вопрос ).
А ссылки эти ДРегистры="Группы значений доступа")
ДРегистры="(не используется) Группы значений доступа")
то же удалятся следом за номенклатурой?
(46) caponid, Не все так просто, я не могу их сразу удалить, так как они есть в "установке цен" "Если (ДРегистры="Установка цен номенклатуры")". Я их сначала пометил на удаление, потом другой обработкой прошелся по документам "установке цен", удалил их оттуда, перезаписал документы, а вот только после их можно удалять. Если бы их не было в "установке цен", тогда я с Вами был бы согласен чтобы удалить их сразу
(48) LastSoldier, то что вносишь в исключения - на ссылочный контроль не проверяется - в тех объектах будет вместо этой номенклатуры <Объект не найден>
а они разве не будут удаляться вместе с номенклатурой?
нет конечно.
зачем пустые ссылки в базе.
А кто сказал что "объект не найден" это пустая ссылка? Там как раз все есть. Но оно немного испорчено. Почитайте в тырнете про объект не найден. Поймете.
Или их из базы потом еще самому удалять надо будет?
И это делать не просто. Нужно перебирать все объекты. Смотреть в каждый: он битый или нет.
Тут есть несколько вариантов проверки. Но в любом случае такого лучше не допускать.