[ Разбор вопросов ] Про методы Следующий и СледующийПоЗначениюПоля, а также про команду Движения.ИмяРегистра.Записывать = Истина при проведении по “новой” методике

Сегодня в подборке всего два вопроса. Главное их сходство – это глубина и полнота полученных ответов от тренеров в Мастер-группах. Мы даже не сомневаемся, что первый слушатель уяснил, в чем разница между методами Следующий и СледующийПоЗначениюПоля, а второй – разобрался, почему нельзя использовать последовательность команд Движения.ИмяРегистра.Записывать = Истина и Движения.ИмяРегистра.Записать() при проведении документа по “новой” методике.
 

Вопрос №1: В чем разница методов навигации по записям результата запроса Следующий и СледующийПоЗначениюПоля?

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

Ответ

В общем случае эти методы могут давать разные результаты. Поэтому отметим разницу между методами Следующий и СледующийПоЗначениюПоля:

  1. При помощи метода Следующий происходит позиционирование на следующей записи из результата запроса.
  2. При помощи метода СледующийПоЗначениюПоля выборка позиционируется на следующую запись со значением, отличающимся от текущего значения, по указанному полю.
  3. Могут использоваться вложенные циклы, работающие с одной и той же выборкой:
Выборка = РезультатЗапроса.Выбрать();
    //внешний цикл
Пока Выборка.СледующийПоЗначениюПоля("Товар") Цикл
        //внутренний цикл
     Пока Выборка.СледующийПоЗначениюПоля("Покупатель") Цикл       
            ...        
     КонецЦикла;     
КонецЦикла;

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

Теперь рассмотрим на примере. Пусть у нас есть следующие данные:

Данные

Данные из базы выбираем при помощи такого кода:

Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
                   |    Таблица.НомерСтроки КАК НомерСтроки,
                   |    Таблица.Товар КАК Товар,
                   |    Таблица.Покупатель КАК Покупатель
                   |ИЗ
                   |    Таблица КАК Таблица";
Выборка = Запрос.Выполнить().Выбрать();

Сделаем 4 варианта обработки этой выборки:

  1.  
Пока Выборка.Следующий() Цикл 
     Сообщить("Номер строки - " + Выборка.НомерСтроки);       
КонецЦикла;

Выводит номера строк – 1, 2, 3, 4, 5, 6. Т.е. обходит последовательно все строки исходной таблицы.

  1.  
Пока Выборка.СледующийПоЗначениюПоля("Товар") Цикл     
     Сообщить("Номер строки - " + Выборка.НомерСтроки);           
КонецЦикла;

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

  1.  
Пока Выборка.СледующийПоЗначениюПоля("Товар") Цикл       
        Сообщить("Внешний цикл. Номер строки - " + Выборка.НомерСтроки);     
        Пока Выборка.СледующийПоЗначениюПоля("Покупатель") Цикл           
            Сообщить("Внутренний цикл. Номер строки - " + Выборка.НомерСтроки);                
        КонецЦикла;       
КонецЦикла;

Выводит:

Внешний цикл. Номер строки – 1

Внутренний цикл. Номер строки – 1

Почему именно так? Потому что данный фрагмент кода работает следующим образом:

  1. Во внешнем цикле вызвали метод Выборка.СледующийПоЗначениюПоля(“Товар”) – спозиционировались на первой строке. Затем выполнение кода переходит во вложенный цикл – по покупателям.
  2. Вызвали во вложенном цикле метод Выборка.СледующийПоЗначениюПоля(“Покупатель”) – спозиционировались на первом покупателе (Иванов) для текущего товара (Стол). Это тоже первая строка таблицы.

Поэтому и внешний, и внутренний цикл выводят первую строку таблицы.

Оба цикла завершают свою работу, поскольку все товары во всех строках одинаковы, а также все покупатели во всех строках одинаковы. Больше итераций циклов не будет.

  1.  
Пока Выборка.СледующийПоЗначениюПоля("Товар") Цикл 
     Сообщить("Внешний цикл. Номер строки - " + Выборка.НомерСтроки);      
     Пока Выборка.Следующий() Цикл          
          Сообщить("Внутренний цикл. Номер строки - " + Выборка.НомерСтроки);               
     КонецЦикла;      
КонецЦикла;

Выводит:

Внешний цикл. Номер строки – 1

Внутренний цикл. Номер строки – 1

Внутренний цикл. Номер строки – 2

Внутренний цикл. Номер строки – 3

Внутренний цикл. Номер строки – 4

Внутренний цикл. Номер строки – 5

Внутренний цикл. Номер строки – 6

Внешний цикл выполняется только один раз, поскольку во всех строках таблицы один и тот же товар. А внутренний цикл выполняется 6 раз, обходит все строки таблицы.

Таким образом, нужно просто представлять, как будет работать метод Следующий или СледующийПоЗначениюПоля. И в зависимости от задачи выбирать тот, что подходит для решения задачи.

P.S.

Понимать, как работают запросы и уметь их строить - обязательный навык для всех, кто дорабатывает и внедряет 1С.

После курса Вы сможете:

  • Строить сложные запросы с несколькими источниками данных
  • Уверенно задействовать вложенные запросы и временные таблицы
  • Использовать встроенный язык для обработки результатов запроса
  • Учитывать особенности соединений и объединений нескольких таблиц.
  • Разрабатывать запросы на уровне задач Аттестации 1С:Специалист по платформе.
Программа, стоимость, условия и регистрация в группу: «Запросы в 1С 8.3, Базовый курс (с нуля до уровня Специалист по платформе)» Для всех, кто внедряет и дорабатывает 1С.

 

Вопрос №2: В каких случаях на экзамене 1С:Специалист по платформе 8.3 нужно использовать команду Движения.Записать() и/или команду Движения.ИмяРН.Записать()?

Получил результат экзамена 1C:Специалист по платформе 8.3. Не сдал :( Одна из ошибок сформулирована следующим образом: “При предварительной записи используется метод Движения.ОстаткиНоменклатуры.Записать() (он не сбрасывает флаг Записывать=Истина)”.
 
Не могли бы вы подробно рассказать в каких случаях нужно использовать Движения.Записать(), а  в каких Движения.ИмяРН.Записать()?
 
У меня после контроля остатков (по новой методике) было еще списание себестоимости по другому РН (по старой методике). К заполнению второго регистра претензий нет. Остатки контролировались, себестоимость рассчитывалась правильно. Я так понимаю претензия в том, что набор по первому регистру записывается дважды, сначала при Движения.РН.Записать(), а потом еще раз при окончании проведения.

Ответ

Если в Вашем решении сначала свойство Записывать набора записей регистра было установлено в значение “Истина”, а затем использовался метод Записать() набора записей регистра, то есть была такая последовательность команд:

Движения.ИмяРегистра.Записывать = Истина;
Движения.ИмяРегистра.Записать();

то значением свойства Движения.ИмяРегистра.Записывать после этой последовательности команд останется по прежнему значение “Истина“. И в конце обработки проведения набор записей этого регистра действительно будет записан еще раз.

Для “старой” методики такая ситуация вполне нормальна: первая операция записи (явная, Движения.ИмяРегистра.Записать()) удаляет из базы прежние движения документа, записывая пустой набор (актуально при перепроведении). Вторая операция записи (неявная, в конце обработки проведения, на основании значения Движения.ИмяРегистра.Записывать = Истина) записывает в базу новые, сформированные этим документом движения.

Если же в процессе формирования движений будет выставлен признак отмены проведения (Отказ = Истина), то явно устанавливать значение свойства Движения.ИмяРегистра.Записывать в значение “Ложь” не требуется, так как при этом сама транзакция записи будет отменена, и повторной (в данном случае лишней) записи набора в базу данных не произойдет.

Если же указанная выше последовательность команд

Движения.ИмяРегистра.Записывать = Истина; и Движения.ИмяРегистра.Записать();

использовалась при проведении по “новой” методике, то, скорее всего, здесь и была допущена ошибка.

При “новой” методике предварительное удаление существующих движений не требуется, набор записей регистра записывается один раз – перед контролем остатков. И если запись производилась так, как показано выше, то система действительно выполнит лишнюю запись в базу данных при окончании проведения (т.к. значение свойства Движения.ИмяРегистра.Записывать осталось в значении “Истина”). В этом случае претензия экзаменатора вполне обоснована.

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

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

Вход на сайт

Зарегистрироваться

Подтверждение регистрации будет отправлено на указанный e-mail.

Я подтверждаю, что ознакомлен(а) с Пользовательским соглашением, принимаю его условия и даю свое согласие на обработку моих персональных данных.

Восстановить доступ

E-mail или логин

Ссылка на создание нового пароля будет отправлена на указанный e-mail.