При разработке в среде «1С:Предприятие» одной из самых частых задач является запись или очистка данных в регистрах сведений. Для этого традиционно используется объект НаборЗаписей. Однако начинающие разработчики регулярно сталкиваются с ошибкой «Поле объекта не обнаружено» при попытке установить фильтрацию по измерениям регистра. Выясним причину этого поведения платформы, детально проанализируем архитектуру регистров сведений и разберем несколько правильных вариантов решения этой задачи.
Для того чтобы полностью разобраться в проблеме, рассмотрим два наиболее частых сценария возникновения этой ошибки, с которыми столкнулся автор темы на форуме.
Сценарий 1. Попытка установить отбор по измерению в подчиненном регистре.
В коде автора присутствует следующая строка:
НаборЗаписей = РегистрыСведений.Бригады.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.ТранспортноеСредство.Установить(ТС);
Если для регистра сведений в конфигураторе установлен режим записи «Подчинение регистратору», платформа накладывает жесткое системное ограничение: объект НаборЗаписей в данном режиме позволяет устанавливать отбор только по полю «Регистратор». Никакие измерения (в данном случае ТранспортноеСредство) напрямую использовать в свойстве Отбор нельзя. Попытка обратиться к измерению вызывает исключение «Поле объекта не обнаружено (ТранспортноеСредство)», поскольку этого свойства физически нет в коллекции отборов для подчиненного набора.
Сценарий 2. Ошибка при указании имени документа вместо предопределенного поля.
Пытаясь обойти первую ошибку, разработчики часто совершают вторую ошибку, указывая имя конкретного документа-регистратора:
НаборЗаписей.Отбор.ОформлениеБригады.Установить(СсылкаНаДокумент);
Это приводит к аналогичной ошибке «Поле объекта не обнаружено (ОформлениеБригады)». Платформа ожидает строго предопределенное имя свойства отбора — Регистратор. Ему абсолютно не важно, какой именно документ в данный момент выступает регистратором записей. Правильное обращение всегда должно выглядеть так:
НаборЗаписей.Отбор.Регистратор.Установить(СсылкаНаДокумент);
---
Прежде чем перейти к написанию кода, проанализируем бизнес-логику, которую пытался реализовать автор. В процедуре ОбработкаПроведения документа ОформлениеБригады автор пытается найти записи по конкретному транспортному средству, созданные другими документами, стереть их и записать новые движения текущего документа.
Такой подход является грубым нарушением стандартов разработки «1С» (антипаттерном) по следующим причинам:
---
Рассмотрим подробнее четыре архитектурно верных способа решения этой задачи в зависимости от бизнес-требований вашей системы.
Если бизнес-логика требует хранить историю укомплектования автомобилей бригадами (чтобы знать, кто работал на машине месяц назад), то регистр сведений обязательно должен быть периодическим.
Как это настроить и использовать:
Бригады установите свойство «Периодичность» (например, «По позиции регистратора» или «День»).СрезПоследних регистра сведений. Платформа сама найдет самую «свежую» запись для автомобиля, проигнорировав все предыдущие устаревшие строки.Пример запроса для получения актуальной бригады:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| БригадыСрезПоследних.Грузчик1,
| БригадыСрезПоследних.Грузчик2,
| БригадыСрезПоследних.Водитель
|ИЗ
| РегистрСведений.Бригады.СрезПоследних(&Период, ТранспортноеСредство = &ТранспортноеСредство) КАК БригадыСрезПоследних";
Запрос.УстановитьПараметр("Период", ТекущаяДата());
Запрос.УстановитьПараметр("ТранспортноеСредство", ВыбранноеТС);
РезультатЗапроса = Запрос.Выполнить();
Если история изменений вам абсолютно не важна и на одну машину всегда может быть назначена строго одна бригада (актуальное состояние), то жесткая привязка регистра к документам-регистраторам избыточна. Сделайте регистр независимым.
Как это настроить и использовать:
НаборЗаписей = РегистрыСведений.Бригады.СоздатьНаборЗаписей();
// Здесь отбор по измерению работает без ошибок, так как регистр независимый!
НаборЗаписей.Отбор.ТранспортноеСредство.Установить(ТранспортноеСредство);
// Записываем пустой набор записей — это действие очистит в базе данных все строки по данному автомобилю
НаборЗаписей.Записать();
// Теперь можно создать и записать новую актуальную запись
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.ТранспортноеСредство = ТранспортноеСредство;
НоваяЗапись.Водитель = Водитель;
НоваяЗапись.Грузчик1 = Грузчик1;
НоваяЗапись.Грузчик2 = Грузчик2;
НаборЗаписей.Записать();
Разберем ситуацию, когда регистр обязан оставаться подчиненным регистратору и при этом непериодическим. Чтобы корректно перезаписать движения, нам придется выполнить процедуру в несколько шагов.
Алгоритм действий:
ТранспортноеСредство.Регистратору и считываем данные методом Прочитать().ТранспортноеСредство в прочитанной таблице набора и удаляем ее.Посмотрим на пример кода:
// Шаг 1. Ищем старый регистратор запросом
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Бригады.Регистратор КАК СтарыйРегистратор
|ИЗ
| РегистрСведений.Бригады КАК Бригады
|ГДЕ
| Бригады.ТранспортноеСредство = &ТранспортноеСредство";
Запрос.УстановитьПараметр("ТранспортноеСредство", ТранспортноеСредство);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
СтарыйРегистратор = Выборка.СтарыйРегистратор;
// Шаг 2. Читаем движения старого документа
НаборСтарый = РегистрыСведений.Бригады.СоздатьНаборЗаписей();
НаборСтарый.Отбор.Регистратор.Установить(СтарыйРегистратор);
НаборСтарый.Прочитать();
// Шаг 3. Удаляем нужную строку из набора
ИндексСтроки = НаборСтарый.Количество() - 1;
Пока ИндексСтроки >= 0 Цикл
СтрокаЗаписи = НаборСтарый[ИндексСтроки];
Если СтрокаЗаписи.ТранспортноеСредство = ТранспортноеСредство Тогда
НаборСтарый.Удалить(СтрокаЗаписи);
КонецЕсли;
ИндексСтроки = ИндексСтроки - 1;
КонецЦикла;
// Шаг 4. Перезаписываем движения старого документа (уже без нашего авто)
НаборСтарый.Записать();
КонецЕсли;
Важное предостережение: Крайне не рекомендуется выполнять данный код непосредственно внутри транзакции проведения (в процедуре ОбработкаПроведения). Лучше всего выносить подобные манипуляции во внешние обработчики (например, перед записью документов на клиенте) или использовать независимые регистры сведений.
---
Давайте зафиксируем ключевые правила работы с объектом НаборЗаписей:
Регистратор.